mirror of
https://github.com/linuxkit/linuxkit.git
synced 2026-04-05 06:15:30 +00:00
Upgrade vpnkit vendoring
Signed-off-by: Guillaume Rose <guillaume.rose@docker.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/moby/hyperkit/go"
|
||||
"github.com/moby/vpnkit/go/pkg/vmnet"
|
||||
"github.com/moby/vpnkit/go/pkg/vpnkit"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -435,17 +436,17 @@ func vpnkitPublishPorts(h *hyperkit.HyperKit, publishFlags multipleFlag, portSoc
|
||||
}
|
||||
|
||||
log.Debugf("Creating new VPNKit VMNet on %s", h.VPNKitSock)
|
||||
vmnet, err := vpnkit.NewVmnet(ctx, h.VPNKitSock)
|
||||
vmnetClient, err := vmnet.New(ctx, h.VPNKitSock)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("NewVmnet failed: %v", err)
|
||||
}
|
||||
defer vmnet.Close()
|
||||
defer vmnetClient.Close()
|
||||
|
||||
// Register with VPNKit
|
||||
var vif *vpnkit.Vif
|
||||
var vif *vmnet.Vif
|
||||
if h.VPNKitPreferredIPv4 == "" {
|
||||
log.Debugf("Creating VPNKit VIF for %v", vpnkitUUID)
|
||||
vif, err = vmnet.ConnectVif(vpnkitUUID)
|
||||
vif, err = vmnetClient.ConnectVif(vpnkitUUID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Connection to Vif failed: %v", err)
|
||||
}
|
||||
@@ -455,7 +456,7 @@ func vpnkitPublishPorts(h *hyperkit.HyperKit, publishFlags multipleFlag, portSoc
|
||||
return nil, fmt.Errorf("Failed to parse IP: %s", h.VPNKitPreferredIPv4)
|
||||
}
|
||||
log.Debugf("Creating VPNKit VIF for %v ip=%v", vpnkitUUID, ip)
|
||||
vif, err = vmnet.ConnectVifIP(vpnkitUUID, ip)
|
||||
vif, err = vmnetClient.ConnectVifIP(vpnkitUUID, ip)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Connection to Vif with IP failed: %v", err)
|
||||
}
|
||||
@@ -463,7 +464,7 @@ func vpnkitPublishPorts(h *hyperkit.HyperKit, publishFlags multipleFlag, portSoc
|
||||
log.Debugf("VPNKit UUID:%s IP: %v", vpnkitUUID, vif.IP)
|
||||
|
||||
log.Debugf("Connecting to VPNKit on %s", portSocket)
|
||||
c, err := vpnkit.NewConnection(context.Background(), portSocket)
|
||||
c, err := vpnkit.NewClient(portSocket)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Connection to VPNKit failed: %v", err)
|
||||
}
|
||||
@@ -477,8 +478,14 @@ func vpnkitPublishPorts(h *hyperkit.HyperKit, publishFlags multipleFlag, portSoc
|
||||
}
|
||||
|
||||
log.Debugf("Publishing %s", publish)
|
||||
vp := vpnkit.NewPort(c, p.Protocol, localhost, p.Host, vif.IP, p.Guest)
|
||||
if err = vp.Expose(context.Background()); err != nil {
|
||||
vp := &vpnkit.Port{
|
||||
Proto: vpnkit.Protocol(p.Protocol),
|
||||
OutIP: localhost,
|
||||
OutPort: p.Host,
|
||||
InIP: vif.IP,
|
||||
InPort: p.Guest,
|
||||
}
|
||||
if err = c.Expose(context.Background(), vp); err != nil {
|
||||
return nil, fmt.Errorf("Failed to expose port %s: %v", publish, err)
|
||||
}
|
||||
ports = append(ports, vp)
|
||||
@@ -487,7 +494,7 @@ func vpnkitPublishPorts(h *hyperkit.HyperKit, publishFlags multipleFlag, portSoc
|
||||
// Return cleanup function
|
||||
return func() {
|
||||
for _, vp := range ports {
|
||||
vp.Unexpose(context.Background())
|
||||
c.Unexpose(context.Background(), vp)
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
cloud.google.com/go v0.53.0
|
||||
github.com/Azure/azure-sdk-for-go 26132835cbefa2669a306b777f34b929b56aa0a2
|
||||
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||
github.com/Azure/go-autorest 58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d
|
||||
github.com/Microsoft/go-winio v0.4.8
|
||||
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
|
||||
github.com/ScaleFT/sshkeys 82451a80368171b074c7129d43b47fc2773f6e9f
|
||||
github.com/agl/ed25519 5312a61534124124185d41f09206b9fef1d88403
|
||||
github.com/aws/aws-sdk-go fa107560b5f3528a859a1a1511086646731bb1a8
|
||||
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||
@@ -19,13 +22,11 @@ github.com/docker/docker-credential-helpers 5241b46610f2491efdf9d1c85f1ddf5b02f6
|
||||
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
|
||||
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
|
||||
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
|
||||
github.com/docker/go-p9p 87ae8514a3a2d9684994a6c319f96ba9e18a062e
|
||||
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
||||
github.com/go-ini/ini afbc45e87f3ba324c532d12c71918ef52e0fb194
|
||||
github.com/gogo/protobuf v1.0.0
|
||||
github.com/golang/protobuf v1.1.0
|
||||
github.com/google/uuid 7e072fc3a7be179aee6d3359e46015aa8c995314
|
||||
github.com/googleapis/gax-go 8c5154c0fe5bf18cf649634d4c6df50897a32751
|
||||
github.com/gophercloud/gophercloud b9ea9cb68cf5803ea1567c404b549a783c8264b2
|
||||
github.com/gophercloud/utils 34f5991525d116b3832e0d9409492274f1c06bda
|
||||
github.com/gorilla/context v1.1
|
||||
@@ -33,13 +34,11 @@ github.com/gorilla/mux v1.1
|
||||
github.com/gorilla/websocket 21ab95fa12b9bdd8fecf5fa3586aad941cc98785
|
||||
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
||||
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
|
||||
github.com/linuxkit/virtsock 8e79449dea0735c1c056d814934dd035734cc97c
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.0
|
||||
github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062
|
||||
github.com/moby/datakit 97b3d230535397a813323902c23751e176481a86
|
||||
github.com/moby/hyperkit d65b09c1c28a2bfb6a976c86ecd885d2ee4c71d3
|
||||
github.com/moby/vpnkit 0e4293bb1058598c4b0a406ed171f52573ef414c
|
||||
github.com/moul/anonuuid c6987e46f8a0231504bcd402962749f8dd9970b0
|
||||
github.com/moby/vpnkit 2ffc1dd8a84ea7359dd09b1f4b51bb728d4f46a0
|
||||
github.com/moul/gotty-client e5589f6df35953284b091b8394daa6be6c453469
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||
github.com/opencontainers/image-spec v1.0.1
|
||||
@@ -54,9 +53,7 @@ github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
|
||||
github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
|
||||
github.com/radu-matei/azure-sdk-for-go 3b12823551999669c9a325a32472508e0af7978e
|
||||
github.com/radu-matei/azure-vhd-utils e52754d5569d2a643a7775f72ff2a6cf524f4c25
|
||||
github.com/renstrom/fuzzysearch 7a8f9a1c4bed53899ecd512daeaf8207cc454156
|
||||
github.com/rn/iso9660wrap baf8d62ad3155152b488d5ff9d4f2b9bb0d6986a
|
||||
github.com/ScaleFT/sshkeys 82451a80368171b074c7129d43b47fc2773f6e9f
|
||||
github.com/scaleway/scaleway-sdk-go 20b731586975c078d9c2d7dd0002127e9e9cdef2
|
||||
github.com/sirupsen/logrus v1.0.3
|
||||
github.com/spf13/cobra v0.0.3
|
||||
@@ -73,8 +70,5 @@ golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
|
||||
golang.org/x/oauth2 1611bb46e67abc64a71ecc5c3ae67f1cbbc2b921
|
||||
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
|
||||
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
|
||||
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
|
||||
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
|
||||
google.golang.org/api 373a4c220f5c90e5b7ff7101779c5be385d171be
|
||||
google.golang.org/grpc v1.12.0
|
||||
gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
|
||||
|
||||
2
src/cmd/linuxkit/vendor/cloud.google.com/go/LICENSE
generated
vendored
2
src/cmd/linuxkit/vendor/cloud.google.com/go/LICENSE
generated
vendored
@@ -187,7 +187,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014 Google Inc.
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
559
src/cmd/linuxkit/vendor/cloud.google.com/go/README.md
generated
vendored
559
src/cmd/linuxkit/vendor/cloud.google.com/go/README.md
generated
vendored
@@ -1,188 +1,76 @@
|
||||
# Google Cloud for Go
|
||||
# Google Cloud Client Libraries for Go
|
||||
|
||||
[](https://travis-ci.org/GoogleCloudPlatform/google-cloud-go)
|
||||
[](https://godoc.org/cloud.google.com/go)
|
||||
|
||||
Go packages for [Google Cloud Platform](https://cloud.google.com) services.
|
||||
|
||||
``` go
|
||||
import "cloud.google.com/go"
|
||||
```
|
||||
|
||||
Go packages for Google Cloud Platform services.
|
||||
To install the packages on your system, *do not clone the repo*. Instead:
|
||||
|
||||
To install the packages on your system,
|
||||
1. Change to your project directory:
|
||||
|
||||
```
|
||||
$ go get -u cloud.google.com/go/...
|
||||
```
|
||||
```
|
||||
cd /my/cloud/project
|
||||
```
|
||||
1. Get the package you want to use. Some products have their own module, so it's
|
||||
best to `go get` the package(s) you want to use:
|
||||
|
||||
**NOTE:** These packages are under development, and may occasionally make
|
||||
backwards-incompatible changes.
|
||||
```
|
||||
$ go get cloud.google.com/go/firestore # Replace with the package you want to use.
|
||||
```
|
||||
|
||||
**NOTE:** Some of these packages are under development, and may occasionally
|
||||
make backwards-incompatible changes.
|
||||
|
||||
**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud).
|
||||
|
||||
* [News](#news)
|
||||
* [Supported APIs](#supported-apis)
|
||||
* [Go Versions Supported](#go-versions-supported)
|
||||
* [Authorization](#authorization)
|
||||
* [Cloud Datastore](#cloud-datastore-)
|
||||
* [Cloud Storage](#cloud-storage-)
|
||||
* [Cloud Pub/Sub](#cloud-pub-sub-)
|
||||
* [Cloud BigQuery](#cloud-bigquery-)
|
||||
* [Stackdriver Logging](#stackdriver-logging-)
|
||||
* [Cloud Spanner](#cloud-spanner-)
|
||||
|
||||
|
||||
## News
|
||||
|
||||
_February 14, 2017_
|
||||
|
||||
Release of a client library for Spanner. See
|
||||
the
|
||||
[blog post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html).
|
||||
|
||||
Note that although the Spanner service is beta, the Go client library is alpha.
|
||||
|
||||
_December 12, 2016_
|
||||
|
||||
Beta release of BigQuery, DataStore, Logging and Storage. See the
|
||||
[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html).
|
||||
|
||||
Also, BigQuery now supports structs. Read a row directly into a struct with
|
||||
`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`.
|
||||
You can also use field tags. See the [package documentation][cloud-bigquery-ref]
|
||||
for details.
|
||||
|
||||
_December 5, 2016_
|
||||
|
||||
More changes to BigQuery:
|
||||
|
||||
* The `ValueList` type was removed. It is no longer necessary. Instead of
|
||||
```go
|
||||
var v ValueList
|
||||
... it.Next(&v) ..
|
||||
```
|
||||
use
|
||||
|
||||
```go
|
||||
var v []Value
|
||||
... it.Next(&v) ...
|
||||
```
|
||||
|
||||
* Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or
|
||||
`ValueList` would append to the slice. Now each call resets the size to zero first.
|
||||
|
||||
* Schema inference will infer the SQL type BYTES for a struct field of
|
||||
type []byte. Previously it inferred STRING.
|
||||
|
||||
* The types `uint`, `uint64` and `uintptr` are no longer supported in schema
|
||||
inference. BigQuery's integer type is INT64, and those types may hold values
|
||||
that are not correctly represented in a 64-bit signed integer.
|
||||
|
||||
* The SQL types DATE, TIME and DATETIME are now supported. They correspond to
|
||||
the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil`
|
||||
package.
|
||||
|
||||
_November 17, 2016_
|
||||
|
||||
Change to BigQuery: values from INTEGER columns will now be returned as int64,
|
||||
not int. This will avoid errors arising from large values on 32-bit systems.
|
||||
|
||||
_November 8, 2016_
|
||||
|
||||
New datastore feature: datastore now encodes your nested Go structs as Entity values,
|
||||
instead of a flattened list of the embedded struct's fields.
|
||||
This means that you may now have twice-nested slices, eg.
|
||||
```go
|
||||
type State struct {
|
||||
Cities []struct{
|
||||
Populations []int
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for
|
||||
more details.
|
||||
|
||||
_November 8, 2016_
|
||||
|
||||
Breaking changes to datastore: contexts no longer hold namespaces; instead you
|
||||
must set a key's namespace explicitly. Also, key functions have been changed
|
||||
and renamed.
|
||||
|
||||
* The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method:
|
||||
```go
|
||||
q := datastore.NewQuery("Kind").Namespace("ns")
|
||||
```
|
||||
|
||||
* All the fields of Key are exported. That means you can construct any Key with a struct literal:
|
||||
```go
|
||||
k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"}
|
||||
```
|
||||
|
||||
* As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed.
|
||||
|
||||
* `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace
|
||||
```go
|
||||
NewIncompleteKey(ctx, kind, parent)
|
||||
```
|
||||
with
|
||||
```go
|
||||
IncompleteKey(kind, parent)
|
||||
```
|
||||
and if you do use namespaces, make sure you set the namespace on the returned key.
|
||||
|
||||
* `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace
|
||||
```go
|
||||
NewKey(ctx, kind, name, 0, parent)
|
||||
NewKey(ctx, kind, "", id, parent)
|
||||
```
|
||||
with
|
||||
```go
|
||||
NameKey(kind, name, parent)
|
||||
IDKey(kind, id, parent)
|
||||
```
|
||||
and if you do use namespaces, make sure you set the namespace on the returned key.
|
||||
|
||||
* The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`.
|
||||
|
||||
* The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection.
|
||||
|
||||
See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for
|
||||
more details.
|
||||
|
||||
_October 27, 2016_
|
||||
|
||||
Breaking change to bigquery: `NewGCSReference` is now a function,
|
||||
not a method on `Client`.
|
||||
|
||||
New bigquery feature: `Table.LoaderFrom` now accepts a `ReaderSource`, enabling
|
||||
loading data into a table from a file or any `io.Reader`.
|
||||
|
||||
_October 21, 2016_
|
||||
|
||||
Breaking change to pubsub: removed `pubsub.Done`.
|
||||
|
||||
Use `iterator.Done` instead, where `iterator` is the package
|
||||
`google.golang.org/api/iterator`.
|
||||
|
||||
|
||||
[Older news](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/old-news.md)
|
||||
|
||||
## Supported APIs
|
||||
|
||||
Google API | Status | Package
|
||||
-------------------------------|--------------|-----------------------------------------------------------
|
||||
[Datastore][cloud-datastore] | beta | [`cloud.google.com/go/datastore`][cloud-datastore-ref]
|
||||
[Storage][cloud-storage] | beta | [`cloud.google.com/go/storage`][cloud-storage-ref]
|
||||
[Bigtable][cloud-bigtable] | beta | [`cloud.google.com/go/bigtable`][cloud-bigtable-ref]
|
||||
[BigQuery][cloud-bigquery] | beta | [`cloud.google.com/go/bigquery`][cloud-bigquery-ref]
|
||||
[Logging][cloud-logging] | beta | [`cloud.google.com/go/logging`][cloud-logging-ref]
|
||||
[Pub/Sub][cloud-pubsub] | alpha | [`cloud.google.com/go/pubsub`][cloud-pubsub-ref]
|
||||
[Vision][cloud-vision] | beta | [`cloud.google.com/go/vision`][cloud-vision-ref]
|
||||
[Language][cloud-language] | alpha | [`cloud.google.com/go/language/apiv1`][cloud-language-ref]
|
||||
[Speech][cloud-speech] | alpha | [`cloud.google.com/go/speech/apiv1beta`][cloud-speech-ref]
|
||||
[Spanner][cloud-spanner] | alpha | [`cloud.google.com/go/spanner`][cloud-spanner-ref]
|
||||
|
||||
Google API | Status | Package
|
||||
------------------------------------------------|--------------|-----------------------------------------------------------
|
||||
[Asset][cloud-asset] | alpha | [`cloud.google.com/go/asset/v1beta`](https://godoc.org/cloud.google.com/go/asset/v1beta)
|
||||
[Automl][cloud-automl] | stable | [`cloud.google.com/go/automl/apiv1`](https://godoc.org/cloud.google.com/go/automl/apiv1)
|
||||
[BigQuery][cloud-bigquery] | stable | [`cloud.google.com/go/bigquery`](https://godoc.org/cloud.google.com/go/bigquery)
|
||||
[Bigtable][cloud-bigtable] | stable | [`cloud.google.com/go/bigtable`](https://godoc.org/cloud.google.com/go/bigtable)
|
||||
[Cloudbuild][cloud-build] | stable | [`cloud.google.com/go/cloudbuild/apiv1`](https://godoc.org/cloud.google.com/go/cloudbuild/apiv1)
|
||||
[Cloudtasks][cloud-tasks] | stable | [`cloud.google.com/go/cloudtasks/apiv2`](https://godoc.org/cloud.google.com/go/cloudtasks/apiv2)
|
||||
[Container][cloud-container] | stable | [`cloud.google.com/go/container/apiv1`](https://godoc.org/cloud.google.com/go/container/apiv1)
|
||||
[ContainerAnalysis][cloud-containeranalysis] | beta | [`cloud.google.com/go/containeranalysis/apiv1`](https://godoc.org/cloud.google.com/go/containeranalysis/apiv1)
|
||||
[Dataproc][cloud-dataproc] | stable | [`cloud.google.com/go/dataproc/apiv1`](https://godoc.org/cloud.google.com/go/dataproc/apiv1)
|
||||
[Datastore][cloud-datastore] | stable | [`cloud.google.com/go/datastore`](https://godoc.org/cloud.google.com/go/datastore)
|
||||
[Debugger][cloud-debugger] | stable | [`cloud.google.com/go/debugger/apiv2`](https://godoc.org/cloud.google.com/go/debugger/apiv2)
|
||||
[Dialogflow][cloud-dialogflow] | stable | [`cloud.google.com/go/dialogflow/apiv2`](https://godoc.org/cloud.google.com/go/dialogflow/apiv2)
|
||||
[Data Loss Prevention][cloud-dlp] | stable | [`cloud.google.com/go/dlp/apiv2`](https://godoc.org/cloud.google.com/go/dlp/apiv2)
|
||||
[ErrorReporting][cloud-errors] | alpha | [`cloud.google.com/go/errorreporting`](https://godoc.org/cloud.google.com/go/errorreporting)
|
||||
[Firestore][cloud-firestore] | stable | [`cloud.google.com/go/firestore`](https://godoc.org/cloud.google.com/go/firestore)
|
||||
[IAM][cloud-iam] | stable | [`cloud.google.com/go/iam`](https://godoc.org/cloud.google.com/go/iam)
|
||||
[IoT][cloud-iot] | stable | [`cloud.google.com/go/iot/apiv1`](https://godoc.org/cloud.google.com/go/iot/apiv1)
|
||||
[IRM][cloud-irm] | alpha | [`cloud.google.com/go/irm/apiv1alpha2`](https://godoc.org/cloud.google.com/go/irm/apiv1alpha2)
|
||||
[KMS][cloud-kms] | stable | [`cloud.google.com/go/kms/apiv1`](https://godoc.org/cloud.google.com/go/kms/apiv1)
|
||||
[Natural Language][cloud-natural-language] | stable | [`cloud.google.com/go/language/apiv1`](https://godoc.org/cloud.google.com/go/language/apiv1)
|
||||
[Logging][cloud-logging] | stable | [`cloud.google.com/go/logging`](https://godoc.org/cloud.google.com/go/logging)
|
||||
[Memorystore][cloud-memorystore] | alpha | [`cloud.google.com/go/redis/apiv1`](https://godoc.org/cloud.google.com/go/redis/apiv1)
|
||||
[Monitoring][cloud-monitoring] | alpha | [`cloud.google.com/go/monitoring/apiv3`](https://godoc.org/cloud.google.com/go/monitoring/apiv3)
|
||||
[OS Login][cloud-oslogin] | alpha | [`cloud.google.com/go/oslogin/apiv1`](https://godoc.org/cloud.google.com/go/oslogin/apiv1)
|
||||
[Pub/Sub][cloud-pubsub] | stable | [`cloud.google.com/go/pubsub`](https://godoc.org/cloud.google.com/go/pubsub)
|
||||
[Phishing Protection][cloud-phishingprotection] | alpha | [`cloud.google.com/go/phishingprotection/apiv1beta1`](https://godoc.org/cloud.google.com/go/phishingprotection/apiv1beta1)
|
||||
[reCAPTCHA Enterprise][cloud-recaptcha] | alpha | [`cloud.google.com/go/recaptchaenterprise/apiv1beta1`](https://godoc.org/cloud.google.com/go/recaptchaenterprise/apiv1beta1)
|
||||
[Recommender][cloud-recommender] | beta | [`cloud.google.com/go/recommender/apiv1beta1`](https://godoc.org/cloud.google.com/go/recommender/apiv1beta1)
|
||||
[Scheduler][cloud-scheduler] | stable | [`cloud.google.com/go/scheduler/apiv1`](https://godoc.org/cloud.google.com/go/scheduler/apiv1)
|
||||
[Securitycenter][cloud-securitycenter] | alpha | [`cloud.google.com/go/securitycenter/apiv1`](https://godoc.org/cloud.google.com/go/securitycenter/apiv1)
|
||||
[Spanner][cloud-spanner] | stable | [`cloud.google.com/go/spanner`](https://godoc.org/cloud.google.com/go/spanner)
|
||||
[Speech][cloud-speech] | stable | [`cloud.google.com/go/speech/apiv1`](https://godoc.org/cloud.google.com/go/speech/apiv1)
|
||||
[Storage][cloud-storage] | stable | [`cloud.google.com/go/storage`](https://godoc.org/cloud.google.com/go/storage)
|
||||
[Talent][cloud-talent] | alpha | [`cloud.google.com/go/talent/apiv4beta1`](https://godoc.org/cloud.google.com/go/talent/apiv4beta1)
|
||||
[Text To Speech][cloud-texttospeech] | alpha | [`cloud.google.com/go/texttospeech/apiv1`](https://godoc.org/cloud.google.com/go/texttospeech/apiv1)
|
||||
[Trace][cloud-trace] | alpha | [`cloud.google.com/go/trace/apiv2`](https://godoc.org/cloud.google.com/go/trace/apiv2)
|
||||
[Translate][cloud-translate] | stable | [`cloud.google.com/go/translate`](https://godoc.org/cloud.google.com/go/translate)
|
||||
[Video Intelligence][cloud-video] | alpha | [`cloud.google.com/go/videointelligence/apiv1beta1`](https://godoc.org/cloud.google.com/go/videointelligence/apiv1beta1)
|
||||
[Vision][cloud-vision] | stable | [`cloud.google.com/go/vision/apiv1`](https://godoc.org/cloud.google.com/go/vision/apiv1)
|
||||
[Webrisk][cloud-webrisk] | alpha | [`cloud.google.com/go/webrisk/apiv1beta1`](https://godoc.org/cloud.google.com/go/webrisk/apiv1beta1)
|
||||
|
||||
> **Alpha status**: the API is still being actively developed. As a
|
||||
> result, it might change in backward-incompatible ways and is not recommended
|
||||
@@ -195,26 +83,20 @@ Google API | Status | Package
|
||||
> **Stable status**: the API is mature and ready for production use. We will
|
||||
> continue addressing bugs and feature requests.
|
||||
|
||||
Documentation and examples are available at
|
||||
https://godoc.org/cloud.google.com/go
|
||||
|
||||
Visit or join the
|
||||
[google-api-go-announce group](https://groups.google.com/forum/#!forum/google-api-go-announce)
|
||||
for updates on these packages.
|
||||
Documentation and examples are available at [godoc.org/cloud.google.com/go](https://godoc.org/cloud.google.com/go)
|
||||
|
||||
## Go Versions Supported
|
||||
|
||||
We support the two most recent major versions of Go. If Google App Engine uses
|
||||
an older version, we support that as well. You can see which versions are
|
||||
currently supported by looking at the lines following `go:` in
|
||||
[`.travis.yml`](.travis.yml).
|
||||
an older version, we support that as well.
|
||||
|
||||
## Authorization
|
||||
|
||||
By default, each API will use [Google Application Default Credentials][default-creds]
|
||||
By default, each API will use [Google Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials)
|
||||
for authorization credentials used in calling the API endpoints. This will allow your
|
||||
application to run in many environments without requiring explicit configuration.
|
||||
|
||||
[snip]:# (auth)
|
||||
```go
|
||||
client, err := storage.NewClient(ctx)
|
||||
```
|
||||
@@ -222,11 +104,12 @@ client, err := storage.NewClient(ctx)
|
||||
To authorize using a
|
||||
[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys),
|
||||
pass
|
||||
[`option.WithServiceAccountFile`](https://godoc.org/google.golang.org/api/option#WithServiceAccountFile)
|
||||
[`option.WithCredentialsFile`](https://godoc.org/google.golang.org/api/option#WithCredentialsFile)
|
||||
to the `NewClient` function of the desired package. For example:
|
||||
|
||||
[snip]:# (auth-JSON)
|
||||
```go
|
||||
client, err := storage.NewClient(ctx, option.WithServiceAccountFile("path/to/keyfile.json"))
|
||||
client, err := storage.NewClient(ctx, option.WithCredentialsFile("path/to/keyfile.json"))
|
||||
```
|
||||
|
||||
You can exert more control over authorization by using the
|
||||
@@ -234,247 +117,12 @@ You can exert more control over authorization by using the
|
||||
create an `oauth2.TokenSource`. Then pass
|
||||
[`option.WithTokenSource`](https://godoc.org/google.golang.org/api/option#WithTokenSource)
|
||||
to the `NewClient` function:
|
||||
[snip]:# (auth-ts)
|
||||
```go
|
||||
tokenSource := ...
|
||||
client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource))
|
||||
```
|
||||
|
||||
## Cloud Datastore [](https://godoc.org/cloud.google.com/go/datastore)
|
||||
|
||||
- [About Cloud Datastore][cloud-datastore]
|
||||
- [Activating the API for your project][cloud-datastore-activation]
|
||||
- [API documentation][cloud-datastore-docs]
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/datastore)
|
||||
- [Complete sample program](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/datastore/tasks)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `datastore.Client` to use throughout your application:
|
||||
|
||||
```go
|
||||
client, err := datastore.NewClient(ctx, "my-project-id")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
Then use that client to interact with the API:
|
||||
|
||||
```go
|
||||
type Post struct {
|
||||
Title string
|
||||
Body string `datastore:",noindex"`
|
||||
PublishedAt time.Time
|
||||
}
|
||||
keys := []*datastore.Key{
|
||||
datastore.NewKey(ctx, "Post", "post1", 0, nil),
|
||||
datastore.NewKey(ctx, "Post", "post2", 0, nil),
|
||||
}
|
||||
posts := []*Post{
|
||||
{Title: "Post 1", Body: "...", PublishedAt: time.Now()},
|
||||
{Title: "Post 2", Body: "...", PublishedAt: time.Now()},
|
||||
}
|
||||
if _, err := client.PutMulti(ctx, keys, posts); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
## Cloud Storage [](https://godoc.org/cloud.google.com/go/storage)
|
||||
|
||||
- [About Cloud Storage][cloud-storage]
|
||||
- [API documentation][cloud-storage-docs]
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/storage)
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `storage.Client` to use throughout your application:
|
||||
|
||||
```go
|
||||
client, err := storage.NewClient(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// Read the object1 from bucket.
|
||||
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rc.Close()
|
||||
body, err := ioutil.ReadAll(rc)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
## Cloud Pub/Sub [](https://godoc.org/cloud.google.com/go/pubsub)
|
||||
|
||||
- [About Cloud Pubsub][cloud-pubsub]
|
||||
- [API documentation][cloud-pubsub-docs]
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/pubsub)
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/pubsub)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `pubsub.Client` to use throughout your application:
|
||||
|
||||
```go
|
||||
client, err := pubsub.NewClient(ctx, "project-id")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
Then use the client to publish and subscribe:
|
||||
|
||||
```go
|
||||
// Publish "hello world" on topic1.
|
||||
topic := client.Topic("topic1")
|
||||
msgIDs, err := topic.Publish(ctx, &pubsub.Message{
|
||||
Data: []byte("hello world"),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Create an iterator to pull messages via subscription1.
|
||||
it, err := client.Subscription("subscription1").Pull(ctx)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer it.Stop()
|
||||
|
||||
// Consume N messages from the iterator.
|
||||
for i := 0; i < N; i++ {
|
||||
msg, err := it.Next()
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to retrieve message: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Message %d: %s\n", i, msg.Data)
|
||||
msg.Done(true) // Acknowledge that we've consumed the message.
|
||||
}
|
||||
```
|
||||
|
||||
## Cloud BigQuery [](https://godoc.org/cloud.google.com/go/bigquery)
|
||||
|
||||
- [About Cloud BigQuery][cloud-bigquery]
|
||||
- [API documentation][cloud-bigquery-docs]
|
||||
- [Go client documentation][cloud-bigquery-ref]
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/bigquery)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `bigquery.Client` to use throughout your application:
|
||||
```go
|
||||
c, err := bigquery.NewClient(ctx, "my-project-ID")
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
```
|
||||
Then use that client to interact with the API:
|
||||
```go
|
||||
// Construct a query.
|
||||
q := c.Query(`
|
||||
SELECT year, SUM(number)
|
||||
FROM [bigquery-public-data:usa_names.usa_1910_2013]
|
||||
WHERE name = "William"
|
||||
GROUP BY year
|
||||
ORDER BY year
|
||||
`)
|
||||
// Execute the query.
|
||||
it, err := q.Read(ctx)
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// Iterate through the results.
|
||||
for {
|
||||
var values []bigquery.Value
|
||||
err := it.Next(&values)
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
fmt.Println(values)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Stackdriver Logging [](https://godoc.org/cloud.google.com/go/logging)
|
||||
|
||||
- [About Stackdriver Logging][cloud-logging]
|
||||
- [API documentation][cloud-logging-docs]
|
||||
- [Go client documentation][cloud-logging-ref]
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/logging)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `logging.Client` to use throughout your application:
|
||||
|
||||
```go
|
||||
ctx := context.Background()
|
||||
client, err := logging.NewClient(ctx, "my-project")
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
```
|
||||
Usually, you'll want to add log entries to a buffer to be periodically flushed
|
||||
(automatically and asynchronously) to the Stackdriver Logging service.
|
||||
```go
|
||||
logger := client.Logger("my-log")
|
||||
logger.Log(logging.Entry{Payload: "something happened!"})
|
||||
```
|
||||
Close your client before your program exits, to flush any buffered log entries.
|
||||
```go
|
||||
err = client.Close()
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Cloud Spanner [](https://godoc.org/cloud.google.com/go/spanner)
|
||||
|
||||
- [About Cloud Spanner][cloud-spanner]
|
||||
- [API documentation][cloud-spanner-docs]
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/spanner)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `spanner.Client` to use throughout your application:
|
||||
|
||||
```go
|
||||
client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// Simple Reads And Writes
|
||||
_, err := client.Apply(ctx, []*spanner.Mutation{
|
||||
spanner.Insert("Users",
|
||||
[]string{"name", "email"},
|
||||
[]interface{}{"alice", "a@example.com"})})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
row, err := client.Single().ReadRow(ctx, "Users",
|
||||
spanner.Key{"alice"}, []string{"email"})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome. Please, see the
|
||||
@@ -487,42 +135,45 @@ By participating in this project you agree to abide by its terms.
|
||||
See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md#contributor-code-of-conduct)
|
||||
for more information.
|
||||
|
||||
[cloud-datastore]: https://cloud.google.com/datastore/
|
||||
[cloud-datastore-ref]: https://godoc.org/cloud.google.com/go/datastore
|
||||
[cloud-datastore-docs]: https://cloud.google.com/datastore/docs
|
||||
[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate
|
||||
|
||||
[cloud-pubsub]: https://cloud.google.com/pubsub/
|
||||
[cloud-pubsub-ref]: https://godoc.org/cloud.google.com/go/pubsub
|
||||
[cloud-pubsub-docs]: https://cloud.google.com/pubsub/docs
|
||||
|
||||
[cloud-storage]: https://cloud.google.com/storage/
|
||||
[cloud-storage-ref]: https://godoc.org/cloud.google.com/go/storage
|
||||
[cloud-storage-docs]: https://cloud.google.com/storage/docs
|
||||
[cloud-storage-create-bucket]: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets
|
||||
|
||||
[cloud-bigtable]: https://cloud.google.com/bigtable/
|
||||
[cloud-bigtable-ref]: https://godoc.org/cloud.google.com/go/bigtable
|
||||
|
||||
[cloud-asset]: https://cloud.google.com/security-command-center/docs/how-to-asset-inventory
|
||||
[cloud-automl]: https://cloud.google.com/automl
|
||||
[cloud-build]: https://cloud.google.com/cloud-build/
|
||||
[cloud-bigquery]: https://cloud.google.com/bigquery/
|
||||
[cloud-bigquery-docs]: https://cloud.google.com/bigquery/docs
|
||||
[cloud-bigquery-ref]: https://godoc.org/cloud.google.com/go/bigquery
|
||||
|
||||
[cloud-logging]: https://cloud.google.com/logging/
|
||||
[cloud-logging-docs]: https://cloud.google.com/logging/docs
|
||||
[cloud-logging-ref]: https://godoc.org/cloud.google.com/go/logging
|
||||
|
||||
[cloud-vision]: https://cloud.google.com/vision/
|
||||
[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision
|
||||
|
||||
[cloud-bigtable]: https://cloud.google.com/bigtable/
|
||||
[cloud-container]: https://cloud.google.com/containers/
|
||||
[cloud-containeranalysis]: https://cloud.google.com/container-registry/docs/container-analysis
|
||||
[cloud-dataproc]: https://cloud.google.com/dataproc/
|
||||
[cloud-datastore]: https://cloud.google.com/datastore/
|
||||
[cloud-dialogflow]: https://cloud.google.com/dialogflow-enterprise/
|
||||
[cloud-debugger]: https://cloud.google.com/debugger/
|
||||
[cloud-dlp]: https://cloud.google.com/dlp/
|
||||
[cloud-errors]: https://cloud.google.com/error-reporting/
|
||||
[cloud-firestore]: https://cloud.google.com/firestore/
|
||||
[cloud-iam]: https://cloud.google.com/iam/
|
||||
[cloud-iot]: https://cloud.google.com/iot-core/
|
||||
[cloud-irm]: https://cloud.google.com/incident-response/docs/concepts
|
||||
[cloud-kms]: https://cloud.google.com/kms/
|
||||
[cloud-pubsub]: https://cloud.google.com/pubsub/
|
||||
[cloud-storage]: https://cloud.google.com/storage/
|
||||
[cloud-language]: https://cloud.google.com/natural-language
|
||||
[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1
|
||||
|
||||
[cloud-speech]: https://cloud.google.com/speech
|
||||
[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1beta1
|
||||
|
||||
[cloud-logging]: https://cloud.google.com/logging/
|
||||
[cloud-natural-language]: https://cloud.google.com/natural-language/
|
||||
[cloud-memorystore]: https://cloud.google.com/memorystore/
|
||||
[cloud-monitoring]: https://cloud.google.com/monitoring/
|
||||
[cloud-oslogin]: https://cloud.google.com/compute/docs/oslogin/rest
|
||||
[cloud-phishingprotection]: https://cloud.google.com/phishing-protection/
|
||||
[cloud-securitycenter]: https://cloud.google.com/security-command-center/
|
||||
[cloud-scheduler]: https://cloud.google.com/scheduler
|
||||
[cloud-spanner]: https://cloud.google.com/spanner/
|
||||
[cloud-spanner-ref]: https://godoc.org/cloud.google.com/go/spanner
|
||||
[cloud-spanner-docs]: https://cloud.google.com/spanner/docs
|
||||
|
||||
[default-creds]: https://developers.google.com/identity/protocols/application-default-credentials
|
||||
[cloud-speech]: https://cloud.google.com/speech
|
||||
[cloud-talent]: https://cloud.google.com/solutions/talent-solution/
|
||||
[cloud-tasks]: https://cloud.google.com/tasks/
|
||||
[cloud-texttospeech]: https://cloud.google.com/texttospeech/
|
||||
[cloud-talent]: https://cloud.google.com/solutions/talent-solution/
|
||||
[cloud-trace]: https://cloud.google.com/trace/
|
||||
[cloud-translate]: https://cloud.google.com/translate
|
||||
[cloud-recaptcha]: https://cloud.google.com/recaptcha-enterprise/
|
||||
[cloud-recommender]: https://cloud.google.com/recommendations/
|
||||
[cloud-video]: https://cloud.google.com/video-intelligence/
|
||||
[cloud-vision]: https://cloud.google.com/vision
|
||||
[cloud-webrisk]: https://cloud.google.com/web-risk/
|
||||
|
||||
9
src/cmd/linuxkit/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.h
generated
vendored
Normal file
9
src/cmd/linuxkit/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.h
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// +build ignore
|
||||
|
||||
// Empty include file to generate z symbols
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// EOF
|
||||
472
src/cmd/linuxkit/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab.go
generated
vendored
Normal file
472
src/cmd/linuxkit/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab.go
generated
vendored
Normal file
@@ -0,0 +1,472 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*
|
||||
* Line tables
|
||||
*/
|
||||
|
||||
package gosym
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A LineTable is a data structure mapping program counters to line numbers.
|
||||
//
|
||||
// In Go 1.1 and earlier, each function (represented by a Func) had its own LineTable,
|
||||
// and the line number corresponded to a numbering of all source lines in the
|
||||
// program, across all files. That absolute line number would then have to be
|
||||
// converted separately to a file name and line number within the file.
|
||||
//
|
||||
// In Go 1.2, the format of the data changed so that there is a single LineTable
|
||||
// for the entire program, shared by all Funcs, and there are no absolute line
|
||||
// numbers, just line numbers within specific files.
|
||||
//
|
||||
// For the most part, LineTable's methods should be treated as an internal
|
||||
// detail of the package; callers should use the methods on Table instead.
|
||||
type LineTable struct {
|
||||
Data []byte
|
||||
PC uint64
|
||||
Line int
|
||||
|
||||
// Go 1.2 state
|
||||
mu sync.Mutex
|
||||
go12 int // is this in Go 1.2 format? -1 no, 0 unknown, 1 yes
|
||||
binary binary.ByteOrder
|
||||
quantum uint32
|
||||
ptrsize uint32
|
||||
functab []byte
|
||||
nfunctab uint32
|
||||
filetab []byte
|
||||
nfiletab uint32
|
||||
fileMap map[string]uint32
|
||||
}
|
||||
|
||||
// NOTE(rsc): This is wrong for GOARCH=arm, which uses a quantum of 4,
|
||||
// but we have no idea whether we're using arm or not. This only
|
||||
// matters in the old (pre-Go 1.2) symbol table format, so it's not worth
|
||||
// fixing.
|
||||
const oldQuantum = 1
|
||||
|
||||
func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
|
||||
// The PC/line table can be thought of as a sequence of
|
||||
// <pc update>* <line update>
|
||||
// batches. Each update batch results in a (pc, line) pair,
|
||||
// where line applies to every PC from pc up to but not
|
||||
// including the pc of the next pair.
|
||||
//
|
||||
// Here we process each update individually, which simplifies
|
||||
// the code, but makes the corner cases more confusing.
|
||||
b, pc, line = t.Data, t.PC, t.Line
|
||||
for pc <= targetPC && line != targetLine && len(b) > 0 {
|
||||
code := b[0]
|
||||
b = b[1:]
|
||||
switch {
|
||||
case code == 0:
|
||||
if len(b) < 4 {
|
||||
b = b[0:0]
|
||||
break
|
||||
}
|
||||
val := binary.BigEndian.Uint32(b)
|
||||
b = b[4:]
|
||||
line += int(val)
|
||||
case code <= 64:
|
||||
line += int(code)
|
||||
case code <= 128:
|
||||
line -= int(code - 64)
|
||||
default:
|
||||
pc += oldQuantum * uint64(code-128)
|
||||
continue
|
||||
}
|
||||
pc += oldQuantum
|
||||
}
|
||||
return b, pc, line
|
||||
}
|
||||
|
||||
func (t *LineTable) slice(pc uint64) *LineTable {
|
||||
data, pc, line := t.parse(pc, -1)
|
||||
return &LineTable{Data: data, PC: pc, Line: line}
|
||||
}
|
||||
|
||||
// PCToLine returns the line number for the given program counter.
|
||||
// Callers should use Table's PCToLine method instead.
|
||||
func (t *LineTable) PCToLine(pc uint64) int {
|
||||
if t.isGo12() {
|
||||
return t.go12PCToLine(pc)
|
||||
}
|
||||
_, _, line := t.parse(pc, -1)
|
||||
return line
|
||||
}
|
||||
|
||||
// LineToPC returns the program counter for the given line number,
|
||||
// considering only program counters before maxpc.
|
||||
// Callers should use Table's LineToPC method instead.
|
||||
func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 {
|
||||
if t.isGo12() {
|
||||
return 0
|
||||
}
|
||||
_, pc, line1 := t.parse(maxpc, line)
|
||||
if line1 != line {
|
||||
return 0
|
||||
}
|
||||
// Subtract quantum from PC to account for post-line increment
|
||||
return pc - oldQuantum
|
||||
}
|
||||
|
||||
// NewLineTable returns a new PC/line table
|
||||
// corresponding to the encoded data.
|
||||
// Text must be the start address of the
|
||||
// corresponding text segment.
|
||||
func NewLineTable(data []byte, text uint64) *LineTable {
|
||||
return &LineTable{Data: data, PC: text, Line: 0}
|
||||
}
|
||||
|
||||
// Go 1.2 symbol table format.
|
||||
// See golang.org/s/go12symtab.
|
||||
//
|
||||
// A general note about the methods here: rather than try to avoid
|
||||
// index out of bounds errors, we trust Go to detect them, and then
|
||||
// we recover from the panics and treat them as indicative of a malformed
|
||||
// or incomplete table.
|
||||
//
|
||||
// The methods called by symtab.go, which begin with "go12" prefixes,
|
||||
// are expected to have that recovery logic.
|
||||
|
||||
// isGo12 reports whether this is a Go 1.2 (or later) symbol table.
|
||||
func (t *LineTable) isGo12() bool {
|
||||
t.go12Init()
|
||||
return t.go12 == 1
|
||||
}
|
||||
|
||||
const go12magic = 0xfffffffb
|
||||
|
||||
// uintptr returns the pointer-sized value encoded at b.
|
||||
// The pointer size is dictated by the table being read.
|
||||
func (t *LineTable) uintptr(b []byte) uint64 {
|
||||
if t.ptrsize == 4 {
|
||||
return uint64(t.binary.Uint32(b))
|
||||
}
|
||||
return t.binary.Uint64(b)
|
||||
}
|
||||
|
||||
// go12init initializes the Go 1.2 metadata if t is a Go 1.2 symbol table.
|
||||
func (t *LineTable) go12Init() {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.go12 != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// If we panic parsing, assume it's not a Go 1.2 symbol table.
|
||||
recover()
|
||||
}()
|
||||
|
||||
// Check header: 4-byte magic, two zeros, pc quantum, pointer size.
|
||||
t.go12 = -1 // not Go 1.2 until proven otherwise
|
||||
if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 ||
|
||||
(t.Data[6] != 1 && t.Data[6] != 4) || // pc quantum
|
||||
(t.Data[7] != 4 && t.Data[7] != 8) { // pointer size
|
||||
return
|
||||
}
|
||||
|
||||
switch uint32(go12magic) {
|
||||
case binary.LittleEndian.Uint32(t.Data):
|
||||
t.binary = binary.LittleEndian
|
||||
case binary.BigEndian.Uint32(t.Data):
|
||||
t.binary = binary.BigEndian
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
t.quantum = uint32(t.Data[6])
|
||||
t.ptrsize = uint32(t.Data[7])
|
||||
|
||||
t.nfunctab = uint32(t.uintptr(t.Data[8:]))
|
||||
t.functab = t.Data[8+t.ptrsize:]
|
||||
functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
|
||||
fileoff := t.binary.Uint32(t.functab[functabsize:])
|
||||
t.functab = t.functab[:functabsize]
|
||||
t.filetab = t.Data[fileoff:]
|
||||
t.nfiletab = t.binary.Uint32(t.filetab)
|
||||
t.filetab = t.filetab[:t.nfiletab*4]
|
||||
|
||||
t.go12 = 1 // so far so good
|
||||
}
|
||||
|
||||
// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12Funcs() []Func {
|
||||
// Assume it is malformed and return nil on error.
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
|
||||
n := len(t.functab) / int(t.ptrsize) / 2
|
||||
funcs := make([]Func, n)
|
||||
for i := range funcs {
|
||||
f := &funcs[i]
|
||||
f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
|
||||
f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
|
||||
info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
|
||||
f.LineTable = t
|
||||
f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
|
||||
f.Sym = &Sym{
|
||||
Value: f.Entry,
|
||||
Type: 'T',
|
||||
Name: t.string(t.binary.Uint32(info[t.ptrsize:])),
|
||||
GoType: 0,
|
||||
Func: f,
|
||||
}
|
||||
}
|
||||
return funcs
|
||||
}
|
||||
|
||||
// findFunc returns the func corresponding to the given program counter.
|
||||
func (t *LineTable) findFunc(pc uint64) []byte {
|
||||
if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The function table is a list of 2*nfunctab+1 uintptrs,
|
||||
// alternating program counters and offsets to func structures.
|
||||
f := t.functab
|
||||
nf := t.nfunctab
|
||||
for nf > 0 {
|
||||
m := nf / 2
|
||||
fm := f[2*t.ptrsize*m:]
|
||||
if t.uintptr(fm) <= pc && pc < t.uintptr(fm[2*t.ptrsize:]) {
|
||||
return t.Data[t.uintptr(fm[t.ptrsize:]):]
|
||||
} else if pc < t.uintptr(fm) {
|
||||
nf = m
|
||||
} else {
|
||||
f = f[(m+1)*2*t.ptrsize:]
|
||||
nf -= m + 1
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readvarint reads, removes, and returns a varint from *pp.
|
||||
func (t *LineTable) readvarint(pp *[]byte) uint32 {
|
||||
var v, shift uint32
|
||||
p := *pp
|
||||
for shift = 0; ; shift += 7 {
|
||||
b := p[0]
|
||||
p = p[1:]
|
||||
v |= (uint32(b) & 0x7F) << shift
|
||||
if b&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
*pp = p
|
||||
return v
|
||||
}
|
||||
|
||||
// string returns a Go string found at off.
|
||||
func (t *LineTable) string(off uint32) string {
|
||||
for i := off; ; i++ {
|
||||
if t.Data[i] == 0 {
|
||||
return string(t.Data[off:i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step advances to the next pc, value pair in the encoded table.
|
||||
func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
|
||||
uvdelta := t.readvarint(p)
|
||||
if uvdelta == 0 && !first {
|
||||
return false
|
||||
}
|
||||
if uvdelta&1 != 0 {
|
||||
uvdelta = ^(uvdelta >> 1)
|
||||
} else {
|
||||
uvdelta >>= 1
|
||||
}
|
||||
vdelta := int32(uvdelta)
|
||||
pcdelta := t.readvarint(p) * t.quantum
|
||||
*pc += uint64(pcdelta)
|
||||
*val += vdelta
|
||||
return true
|
||||
}
|
||||
|
||||
// pcvalue reports the value associated with the target pc.
|
||||
// off is the offset to the beginning of the pc-value table,
|
||||
// and entry is the start PC for the corresponding function.
|
||||
func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
|
||||
if off == 0 {
|
||||
return -1
|
||||
}
|
||||
p := t.Data[off:]
|
||||
|
||||
val := int32(-1)
|
||||
pc := entry
|
||||
for t.step(&p, &pc, &val, pc == entry) {
|
||||
if targetpc < pc {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// findFileLine scans one function in the binary looking for a
|
||||
// program counter in the given file on the given line.
|
||||
// It does so by running the pc-value tables mapping program counter
|
||||
// to file number. Since most functions come from a single file, these
|
||||
// are usually short and quick to scan. If a file match is found, then the
|
||||
// code goes to the expense of looking for a simultaneous line number match.
|
||||
func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32) uint64 {
|
||||
if filetab == 0 || linetab == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
fp := t.Data[filetab:]
|
||||
fl := t.Data[linetab:]
|
||||
fileVal := int32(-1)
|
||||
filePC := entry
|
||||
lineVal := int32(-1)
|
||||
linePC := entry
|
||||
fileStartPC := filePC
|
||||
for t.step(&fp, &filePC, &fileVal, filePC == entry) {
|
||||
if fileVal == filenum && fileStartPC < filePC {
|
||||
// fileVal is in effect starting at fileStartPC up to
|
||||
// but not including filePC, and it's the file we want.
|
||||
// Run the PC table looking for a matching line number
|
||||
// or until we reach filePC.
|
||||
lineStartPC := linePC
|
||||
for linePC < filePC && t.step(&fl, &linePC, &lineVal, linePC == entry) {
|
||||
// lineVal is in effect until linePC, and lineStartPC < filePC.
|
||||
if lineVal == line {
|
||||
if fileStartPC <= lineStartPC {
|
||||
return lineStartPC
|
||||
}
|
||||
if fileStartPC < linePC {
|
||||
return fileStartPC
|
||||
}
|
||||
}
|
||||
lineStartPC = linePC
|
||||
}
|
||||
}
|
||||
fileStartPC = filePC
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// go12PCToLine maps program counter to line number for the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12PCToLine(pc uint64) (line int) {
|
||||
return t.go12PCToVal(pc, t.ptrsize+5*4)
|
||||
}
|
||||
|
||||
// go12PCToSPAdj maps program counter to Stack Pointer adjustment for the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12PCToSPAdj(pc uint64) (spadj int) {
|
||||
return t.go12PCToVal(pc, t.ptrsize+3*4)
|
||||
}
|
||||
|
||||
func (t *LineTable) go12PCToVal(pc uint64, fOffset uint32) (val int) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
val = -1
|
||||
}
|
||||
}()
|
||||
|
||||
f := t.findFunc(pc)
|
||||
if f == nil {
|
||||
return -1
|
||||
}
|
||||
entry := t.uintptr(f)
|
||||
linetab := t.binary.Uint32(f[fOffset:])
|
||||
return int(t.pcvalue(linetab, entry, pc))
|
||||
}
|
||||
|
||||
// go12PCToFile maps program counter to file name for the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12PCToFile(pc uint64) (file string) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
file = ""
|
||||
}
|
||||
}()
|
||||
|
||||
f := t.findFunc(pc)
|
||||
if f == nil {
|
||||
return ""
|
||||
}
|
||||
entry := t.uintptr(f)
|
||||
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
|
||||
fno := t.pcvalue(filetab, entry, pc)
|
||||
if fno <= 0 {
|
||||
return ""
|
||||
}
|
||||
return t.string(t.binary.Uint32(t.filetab[4*fno:]))
|
||||
}
|
||||
|
||||
// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2 pcln table.
|
||||
func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
pc = 0
|
||||
}
|
||||
}()
|
||||
|
||||
t.initFileMap()
|
||||
filenum := t.fileMap[file]
|
||||
if filenum == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Scan all functions.
|
||||
// If this turns out to be a bottleneck, we could build a map[int32][]int32
|
||||
// mapping file number to a list of functions with code from that file.
|
||||
for i := uint32(0); i < t.nfunctab; i++ {
|
||||
f := t.Data[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
|
||||
entry := t.uintptr(f)
|
||||
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
|
||||
linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
|
||||
pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line))
|
||||
if pc != 0 {
|
||||
return pc
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// initFileMap initializes the map from file name to file number.
|
||||
func (t *LineTable) initFileMap() {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if t.fileMap != nil {
|
||||
return
|
||||
}
|
||||
m := make(map[string]uint32)
|
||||
|
||||
for i := uint32(1); i < t.nfiletab; i++ {
|
||||
s := t.string(t.binary.Uint32(t.filetab[4*i:]))
|
||||
m[s] = i
|
||||
}
|
||||
t.fileMap = m
|
||||
}
|
||||
|
||||
// go12MapFiles adds to m a key for every file in the Go 1.2 LineTable.
|
||||
// Every key maps to obj. That's not a very interesting map, but it provides
|
||||
// a way for callers to obtain the list of files in the program.
|
||||
func (t *LineTable) go12MapFiles(m map[string]*Obj, obj *Obj) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
|
||||
t.initFileMap()
|
||||
for file := range t.fileMap {
|
||||
m[file] = obj
|
||||
}
|
||||
}
|
||||
731
src/cmd/linuxkit/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/symtab.go
generated
vendored
Normal file
731
src/cmd/linuxkit/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/symtab.go
generated
vendored
Normal file
@@ -0,0 +1,731 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package gosym implements access to the Go symbol
|
||||
// and line number tables embedded in Go binaries generated
|
||||
// by the gc compilers.
|
||||
package gosym
|
||||
|
||||
// The table format is a variant of the format used in Plan 9's a.out
|
||||
// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out.
|
||||
// The best reference for the differences between the Plan 9 format
|
||||
// and the Go format is the runtime source, specifically ../../runtime/symtab.c.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
* Symbols
|
||||
*/
|
||||
|
||||
// A Sym represents a single symbol table entry.
|
||||
type Sym struct {
|
||||
Value uint64
|
||||
Type byte
|
||||
Name string
|
||||
GoType uint64
|
||||
// If this symbol if a function symbol, the corresponding Func
|
||||
Func *Func
|
||||
}
|
||||
|
||||
// Static reports whether this symbol is static (not visible outside its file).
|
||||
func (s *Sym) Static() bool { return s.Type >= 'a' }
|
||||
|
||||
// PackageName returns the package part of the symbol name,
|
||||
// or the empty string if there is none.
|
||||
func (s *Sym) PackageName() string {
|
||||
if i := strings.Index(s.Name, "."); i != -1 {
|
||||
return s.Name[0:i]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ReceiverName returns the receiver type name of this symbol,
|
||||
// or the empty string if there is none.
|
||||
func (s *Sym) ReceiverName() string {
|
||||
l := strings.Index(s.Name, ".")
|
||||
r := strings.LastIndex(s.Name, ".")
|
||||
if l == -1 || r == -1 || l == r {
|
||||
return ""
|
||||
}
|
||||
return s.Name[l+1 : r]
|
||||
}
|
||||
|
||||
// BaseName returns the symbol name without the package or receiver name.
|
||||
func (s *Sym) BaseName() string {
|
||||
if i := strings.LastIndex(s.Name, "."); i != -1 {
|
||||
return s.Name[i+1:]
|
||||
}
|
||||
return s.Name
|
||||
}
|
||||
|
||||
// A Func collects information about a single function.
|
||||
type Func struct {
|
||||
Entry uint64
|
||||
*Sym
|
||||
End uint64
|
||||
Params []*Sym
|
||||
Locals []*Sym
|
||||
FrameSize int
|
||||
LineTable *LineTable
|
||||
Obj *Obj
|
||||
}
|
||||
|
||||
// An Obj represents a collection of functions in a symbol table.
|
||||
//
|
||||
// The exact method of division of a binary into separate Objs is an internal detail
|
||||
// of the symbol table format.
|
||||
//
|
||||
// In early versions of Go each source file became a different Obj.
|
||||
//
|
||||
// In Go 1 and Go 1.1, each package produced one Obj for all Go sources
|
||||
// and one Obj per C source file.
|
||||
//
|
||||
// In Go 1.2, there is a single Obj for the entire program.
|
||||
type Obj struct {
|
||||
// Funcs is a list of functions in the Obj.
|
||||
Funcs []Func
|
||||
|
||||
// In Go 1.1 and earlier, Paths is a list of symbols corresponding
|
||||
// to the source file names that produced the Obj.
|
||||
// In Go 1.2, Paths is nil.
|
||||
// Use the keys of Table.Files to obtain a list of source files.
|
||||
Paths []Sym // meta
|
||||
}
|
||||
|
||||
/*
|
||||
* Symbol tables
|
||||
*/
|
||||
|
||||
// Table represents a Go symbol table. It stores all of the
|
||||
// symbols decoded from the program and provides methods to translate
|
||||
// between symbols, names, and addresses.
|
||||
type Table struct {
|
||||
Syms []Sym
|
||||
Funcs []Func
|
||||
Files map[string]*Obj // nil for Go 1.2 and later binaries
|
||||
Objs []Obj // nil for Go 1.2 and later binaries
|
||||
|
||||
go12line *LineTable // Go 1.2 line number table
|
||||
}
|
||||
|
||||
type sym struct {
|
||||
value uint64
|
||||
gotype uint64
|
||||
typ byte
|
||||
name []byte
|
||||
}
|
||||
|
||||
var (
|
||||
littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}
|
||||
bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00}
|
||||
oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
|
||||
)
|
||||
|
||||
func walksymtab(data []byte, fn func(sym) error) error {
|
||||
if len(data) == 0 { // missing symtab is okay
|
||||
return nil
|
||||
}
|
||||
var order binary.ByteOrder = binary.BigEndian
|
||||
newTable := false
|
||||
switch {
|
||||
case bytes.HasPrefix(data, oldLittleEndianSymtab):
|
||||
// Same as Go 1.0, but little endian.
|
||||
// Format was used during interim development between Go 1.0 and Go 1.1.
|
||||
// Should not be widespread, but easy to support.
|
||||
data = data[6:]
|
||||
order = binary.LittleEndian
|
||||
case bytes.HasPrefix(data, bigEndianSymtab):
|
||||
newTable = true
|
||||
case bytes.HasPrefix(data, littleEndianSymtab):
|
||||
newTable = true
|
||||
order = binary.LittleEndian
|
||||
}
|
||||
var ptrsz int
|
||||
if newTable {
|
||||
if len(data) < 8 {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
ptrsz = int(data[7])
|
||||
if ptrsz != 4 && ptrsz != 8 {
|
||||
return &DecodingError{7, "invalid pointer size", ptrsz}
|
||||
}
|
||||
data = data[8:]
|
||||
}
|
||||
var s sym
|
||||
p := data
|
||||
for len(p) >= 4 {
|
||||
var typ byte
|
||||
if newTable {
|
||||
// Symbol type, value, Go type.
|
||||
typ = p[0] & 0x3F
|
||||
wideValue := p[0]&0x40 != 0
|
||||
goType := p[0]&0x80 != 0
|
||||
if typ < 26 {
|
||||
typ += 'A'
|
||||
} else {
|
||||
typ += 'a' - 26
|
||||
}
|
||||
s.typ = typ
|
||||
p = p[1:]
|
||||
if wideValue {
|
||||
if len(p) < ptrsz {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
// fixed-width value
|
||||
if ptrsz == 8 {
|
||||
s.value = order.Uint64(p[0:8])
|
||||
p = p[8:]
|
||||
} else {
|
||||
s.value = uint64(order.Uint32(p[0:4]))
|
||||
p = p[4:]
|
||||
}
|
||||
} else {
|
||||
// varint value
|
||||
s.value = 0
|
||||
shift := uint(0)
|
||||
for len(p) > 0 && p[0]&0x80 != 0 {
|
||||
s.value |= uint64(p[0]&0x7F) << shift
|
||||
shift += 7
|
||||
p = p[1:]
|
||||
}
|
||||
if len(p) == 0 {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
s.value |= uint64(p[0]) << shift
|
||||
p = p[1:]
|
||||
}
|
||||
if goType {
|
||||
if len(p) < ptrsz {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
// fixed-width go type
|
||||
if ptrsz == 8 {
|
||||
s.gotype = order.Uint64(p[0:8])
|
||||
p = p[8:]
|
||||
} else {
|
||||
s.gotype = uint64(order.Uint32(p[0:4]))
|
||||
p = p[4:]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Value, symbol type.
|
||||
s.value = uint64(order.Uint32(p[0:4]))
|
||||
if len(p) < 5 {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
typ = p[4]
|
||||
if typ&0x80 == 0 {
|
||||
return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
|
||||
}
|
||||
typ &^= 0x80
|
||||
s.typ = typ
|
||||
p = p[5:]
|
||||
}
|
||||
|
||||
// Name.
|
||||
var i int
|
||||
var nnul int
|
||||
for i = 0; i < len(p); i++ {
|
||||
if p[i] == 0 {
|
||||
nnul = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
switch typ {
|
||||
case 'z', 'Z':
|
||||
p = p[i+nnul:]
|
||||
for i = 0; i+2 <= len(p); i += 2 {
|
||||
if p[i] == 0 && p[i+1] == 0 {
|
||||
nnul = 2
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(p) < i+nnul {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
s.name = p[0:i]
|
||||
i += nnul
|
||||
p = p[i:]
|
||||
|
||||
if !newTable {
|
||||
if len(p) < 4 {
|
||||
return &DecodingError{len(data), "unexpected EOF", nil}
|
||||
}
|
||||
// Go type.
|
||||
s.gotype = uint64(order.Uint32(p[:4]))
|
||||
p = p[4:]
|
||||
}
|
||||
fn(s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewTable decodes the Go symbol table in data,
|
||||
// returning an in-memory representation.
|
||||
func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
|
||||
var n int
|
||||
err := walksymtab(symtab, func(s sym) error {
|
||||
n++
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var t Table
|
||||
if pcln.isGo12() {
|
||||
t.go12line = pcln
|
||||
}
|
||||
fname := make(map[uint16]string)
|
||||
t.Syms = make([]Sym, 0, n)
|
||||
nf := 0
|
||||
nz := 0
|
||||
lasttyp := uint8(0)
|
||||
err = walksymtab(symtab, func(s sym) error {
|
||||
n := len(t.Syms)
|
||||
t.Syms = t.Syms[0 : n+1]
|
||||
ts := &t.Syms[n]
|
||||
ts.Type = s.typ
|
||||
ts.Value = uint64(s.value)
|
||||
ts.GoType = uint64(s.gotype)
|
||||
switch s.typ {
|
||||
default:
|
||||
// rewrite name to use . instead of · (c2 b7)
|
||||
w := 0
|
||||
b := s.name
|
||||
for i := 0; i < len(b); i++ {
|
||||
if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 {
|
||||
i++
|
||||
b[i] = '.'
|
||||
}
|
||||
b[w] = b[i]
|
||||
w++
|
||||
}
|
||||
ts.Name = string(s.name[0:w])
|
||||
case 'z', 'Z':
|
||||
if lasttyp != 'z' && lasttyp != 'Z' {
|
||||
nz++
|
||||
}
|
||||
for i := 0; i < len(s.name); i += 2 {
|
||||
eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
|
||||
elt, ok := fname[eltIdx]
|
||||
if !ok {
|
||||
return &DecodingError{-1, "bad filename code", eltIdx}
|
||||
}
|
||||
if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
|
||||
ts.Name += "/"
|
||||
}
|
||||
ts.Name += elt
|
||||
}
|
||||
}
|
||||
switch s.typ {
|
||||
case 'T', 't', 'L', 'l':
|
||||
nf++
|
||||
case 'f':
|
||||
fname[uint16(s.value)] = ts.Name
|
||||
}
|
||||
lasttyp = s.typ
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.Funcs = make([]Func, 0, nf)
|
||||
t.Files = make(map[string]*Obj)
|
||||
|
||||
var obj *Obj
|
||||
if t.go12line != nil {
|
||||
// Put all functions into one Obj.
|
||||
t.Objs = make([]Obj, 1)
|
||||
obj = &t.Objs[0]
|
||||
t.go12line.go12MapFiles(t.Files, obj)
|
||||
} else {
|
||||
t.Objs = make([]Obj, 0, nz)
|
||||
}
|
||||
|
||||
// Count text symbols and attach frame sizes, parameters, and
|
||||
// locals to them. Also, find object file boundaries.
|
||||
lastf := 0
|
||||
for i := 0; i < len(t.Syms); i++ {
|
||||
sym := &t.Syms[i]
|
||||
switch sym.Type {
|
||||
case 'Z', 'z': // path symbol
|
||||
if t.go12line != nil {
|
||||
// Go 1.2 binaries have the file information elsewhere. Ignore.
|
||||
break
|
||||
}
|
||||
// Finish the current object
|
||||
if obj != nil {
|
||||
obj.Funcs = t.Funcs[lastf:]
|
||||
}
|
||||
lastf = len(t.Funcs)
|
||||
|
||||
// Start new object
|
||||
n := len(t.Objs)
|
||||
t.Objs = t.Objs[0 : n+1]
|
||||
obj = &t.Objs[n]
|
||||
|
||||
// Count & copy path symbols
|
||||
var end int
|
||||
for end = i + 1; end < len(t.Syms); end++ {
|
||||
if c := t.Syms[end].Type; c != 'Z' && c != 'z' {
|
||||
break
|
||||
}
|
||||
}
|
||||
obj.Paths = t.Syms[i:end]
|
||||
i = end - 1 // loop will i++
|
||||
|
||||
// Record file names
|
||||
depth := 0
|
||||
for j := range obj.Paths {
|
||||
s := &obj.Paths[j]
|
||||
if s.Name == "" {
|
||||
depth--
|
||||
} else {
|
||||
if depth == 0 {
|
||||
t.Files[s.Name] = obj
|
||||
}
|
||||
depth++
|
||||
}
|
||||
}
|
||||
|
||||
case 'T', 't', 'L', 'l': // text symbol
|
||||
if n := len(t.Funcs); n > 0 {
|
||||
t.Funcs[n-1].End = sym.Value
|
||||
}
|
||||
if sym.Name == "etext" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Count parameter and local (auto) syms
|
||||
var np, na int
|
||||
var end int
|
||||
countloop:
|
||||
for end = i + 1; end < len(t.Syms); end++ {
|
||||
switch t.Syms[end].Type {
|
||||
case 'T', 't', 'L', 'l', 'Z', 'z':
|
||||
break countloop
|
||||
case 'p':
|
||||
np++
|
||||
case 'a':
|
||||
na++
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the function symbol
|
||||
n := len(t.Funcs)
|
||||
t.Funcs = t.Funcs[0 : n+1]
|
||||
fn := &t.Funcs[n]
|
||||
sym.Func = fn
|
||||
fn.Params = make([]*Sym, 0, np)
|
||||
fn.Locals = make([]*Sym, 0, na)
|
||||
fn.Sym = sym
|
||||
fn.Entry = sym.Value
|
||||
fn.Obj = obj
|
||||
if t.go12line != nil {
|
||||
// All functions share the same line table.
|
||||
// It knows how to narrow down to a specific
|
||||
// function quickly.
|
||||
fn.LineTable = t.go12line
|
||||
} else if pcln != nil {
|
||||
fn.LineTable = pcln.slice(fn.Entry)
|
||||
pcln = fn.LineTable
|
||||
}
|
||||
for j := i; j < end; j++ {
|
||||
s := &t.Syms[j]
|
||||
switch s.Type {
|
||||
case 'm':
|
||||
fn.FrameSize = int(s.Value)
|
||||
case 'p':
|
||||
n := len(fn.Params)
|
||||
fn.Params = fn.Params[0 : n+1]
|
||||
fn.Params[n] = s
|
||||
case 'a':
|
||||
n := len(fn.Locals)
|
||||
fn.Locals = fn.Locals[0 : n+1]
|
||||
fn.Locals[n] = s
|
||||
}
|
||||
}
|
||||
i = end - 1 // loop will i++
|
||||
}
|
||||
}
|
||||
|
||||
if t.go12line != nil && nf == 0 {
|
||||
t.Funcs = t.go12line.go12Funcs()
|
||||
}
|
||||
if obj != nil {
|
||||
obj.Funcs = t.Funcs[lastf:]
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// PCToFunc returns the function containing the program counter pc,
|
||||
// or nil if there is no such function.
|
||||
func (t *Table) PCToFunc(pc uint64) *Func {
|
||||
funcs := t.Funcs
|
||||
for len(funcs) > 0 {
|
||||
m := len(funcs) / 2
|
||||
fn := &funcs[m]
|
||||
switch {
|
||||
case pc < fn.Entry:
|
||||
funcs = funcs[0:m]
|
||||
case fn.Entry <= pc && pc < fn.End:
|
||||
return fn
|
||||
default:
|
||||
funcs = funcs[m+1:]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PCToLine looks up line number information for a program counter.
|
||||
// If there is no information, it returns fn == nil.
|
||||
func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
|
||||
if fn = t.PCToFunc(pc); fn == nil {
|
||||
return
|
||||
}
|
||||
if t.go12line != nil {
|
||||
file = t.go12line.go12PCToFile(pc)
|
||||
line = t.go12line.go12PCToLine(pc)
|
||||
} else {
|
||||
file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PCToSPAdj returns the stack pointer adjustment for a program counter.
|
||||
func (t *Table) PCToSPAdj(pc uint64) (spadj int) {
|
||||
if fn := t.PCToFunc(pc); fn == nil {
|
||||
return 0
|
||||
}
|
||||
if t.go12line != nil {
|
||||
return t.go12line.go12PCToSPAdj(pc)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// LineToPC looks up the first program counter on the given line in
|
||||
// the named file. It returns UnknownPathError or UnknownLineError if
|
||||
// there is an error looking up this line.
|
||||
func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) {
|
||||
obj, ok := t.Files[file]
|
||||
if !ok {
|
||||
return 0, nil, UnknownFileError(file)
|
||||
}
|
||||
|
||||
if t.go12line != nil {
|
||||
pc := t.go12line.go12LineToPC(file, line)
|
||||
if pc == 0 {
|
||||
return 0, nil, &UnknownLineError{file, line}
|
||||
}
|
||||
return pc, t.PCToFunc(pc), nil
|
||||
}
|
||||
|
||||
abs, err := obj.alineFromLine(file, line)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for i := range obj.Funcs {
|
||||
f := &obj.Funcs[i]
|
||||
pc := f.LineTable.LineToPC(abs, f.End)
|
||||
if pc != 0 {
|
||||
return pc, f, nil
|
||||
}
|
||||
}
|
||||
return 0, nil, &UnknownLineError{file, line}
|
||||
}
|
||||
|
||||
// LookupSym returns the text, data, or bss symbol with the given name,
|
||||
// or nil if no such symbol is found.
|
||||
func (t *Table) LookupSym(name string) *Sym {
|
||||
// TODO(austin) Maybe make a map
|
||||
for i := range t.Syms {
|
||||
s := &t.Syms[i]
|
||||
switch s.Type {
|
||||
case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LookupFunc returns the text, data, or bss symbol with the given name,
|
||||
// or nil if no such symbol is found.
|
||||
func (t *Table) LookupFunc(name string) *Func {
|
||||
for i := range t.Funcs {
|
||||
f := &t.Funcs[i]
|
||||
if f.Sym.Name == name {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SymByAddr returns the text, data, or bss symbol starting at the given address.
|
||||
func (t *Table) SymByAddr(addr uint64) *Sym {
|
||||
for i := range t.Syms {
|
||||
s := &t.Syms[i]
|
||||
switch s.Type {
|
||||
case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
|
||||
if s.Value == addr {
|
||||
return s
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
* Object files
|
||||
*/
|
||||
|
||||
// This is legacy code for Go 1.1 and earlier, which used the
|
||||
// Plan 9 format for pc-line tables. This code was never quite
|
||||
// correct. It's probably very close, and it's usually correct, but
|
||||
// we never quite found all the corner cases.
|
||||
//
|
||||
// Go 1.2 and later use a simpler format, documented at golang.org/s/go12symtab.
|
||||
|
||||
func (o *Obj) lineFromAline(aline int) (string, int) {
|
||||
type stackEnt struct {
|
||||
path string
|
||||
start int
|
||||
offset int
|
||||
prev *stackEnt
|
||||
}
|
||||
|
||||
noPath := &stackEnt{"", 0, 0, nil}
|
||||
tos := noPath
|
||||
|
||||
pathloop:
|
||||
for _, s := range o.Paths {
|
||||
val := int(s.Value)
|
||||
switch {
|
||||
case val > aline:
|
||||
break pathloop
|
||||
|
||||
case val == 1:
|
||||
// Start a new stack
|
||||
tos = &stackEnt{s.Name, val, 0, noPath}
|
||||
|
||||
case s.Name == "":
|
||||
// Pop
|
||||
if tos == noPath {
|
||||
return "<malformed symbol table>", 0
|
||||
}
|
||||
tos.prev.offset += val - tos.start
|
||||
tos = tos.prev
|
||||
|
||||
default:
|
||||
// Push
|
||||
tos = &stackEnt{s.Name, val, 0, tos}
|
||||
}
|
||||
}
|
||||
|
||||
if tos == noPath {
|
||||
return "", 0
|
||||
}
|
||||
return tos.path, aline - tos.start - tos.offset + 1
|
||||
}
|
||||
|
||||
func (o *Obj) alineFromLine(path string, line int) (int, error) {
|
||||
if line < 1 {
|
||||
return 0, &UnknownLineError{path, line}
|
||||
}
|
||||
|
||||
for i, s := range o.Paths {
|
||||
// Find this path
|
||||
if s.Name != path {
|
||||
continue
|
||||
}
|
||||
|
||||
// Find this line at this stack level
|
||||
depth := 0
|
||||
var incstart int
|
||||
line += int(s.Value)
|
||||
pathloop:
|
||||
for _, s := range o.Paths[i:] {
|
||||
val := int(s.Value)
|
||||
switch {
|
||||
case depth == 1 && val >= line:
|
||||
return line - 1, nil
|
||||
|
||||
case s.Name == "":
|
||||
depth--
|
||||
if depth == 0 {
|
||||
break pathloop
|
||||
} else if depth == 1 {
|
||||
line += val - incstart
|
||||
}
|
||||
|
||||
default:
|
||||
if depth == 1 {
|
||||
incstart = val
|
||||
}
|
||||
depth++
|
||||
}
|
||||
}
|
||||
return 0, &UnknownLineError{path, line}
|
||||
}
|
||||
return 0, UnknownFileError(path)
|
||||
}
|
||||
|
||||
/*
|
||||
* Errors
|
||||
*/
|
||||
|
||||
// UnknownFileError represents a failure to find the specific file in
|
||||
// the symbol table.
|
||||
type UnknownFileError string
|
||||
|
||||
func (e UnknownFileError) Error() string { return "unknown file: " + string(e) }
|
||||
|
||||
// UnknownLineError represents a failure to map a line to a program
|
||||
// counter, either because the line is beyond the bounds of the file
|
||||
// or because there is no code on the given line.
|
||||
type UnknownLineError struct {
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
|
||||
func (e *UnknownLineError) Error() string {
|
||||
return "no code at " + e.File + ":" + strconv.Itoa(e.Line)
|
||||
}
|
||||
|
||||
// DecodingError represents an error during the decoding of
|
||||
// the symbol table.
|
||||
type DecodingError struct {
|
||||
off int
|
||||
msg string
|
||||
val interface{}
|
||||
}
|
||||
|
||||
func (e *DecodingError) Error() string {
|
||||
msg := e.msg
|
||||
if e.val != nil {
|
||||
msg += fmt.Sprintf(" '%v'", e.val)
|
||||
}
|
||||
msg += fmt.Sprintf(" at byte %#x", e.off)
|
||||
return msg
|
||||
}
|
||||
508
src/cmd/linuxkit/vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
508
src/cmd/linuxkit/vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
// Copyright 2014 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@
|
||||
package metadata // import "cloud.google.com/go/compute/metadata"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -31,11 +32,6 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
|
||||
"cloud.google.com/go/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -48,6 +44,8 @@ const (
|
||||
// This is variable name is not defined by any spec, as far as
|
||||
// I know; it was made up for the Go package.
|
||||
metadataHostEnv = "GCE_METADATA_HOST"
|
||||
|
||||
userAgent = "gcloud-golang/0.1"
|
||||
)
|
||||
|
||||
type cachedValue struct {
|
||||
@@ -64,27 +62,22 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
metaClient = &http.Client{
|
||||
Transport: &internal.Transport{
|
||||
Base: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
ResponseHeaderTimeout: 2 * time.Second,
|
||||
},
|
||||
defaultClient = &Client{hc: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
},
|
||||
}
|
||||
subscribeClient = &http.Client{
|
||||
Transport: &internal.Transport{
|
||||
Base: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
},
|
||||
}}
|
||||
subscribeClient = &Client{hc: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
},
|
||||
}
|
||||
}}
|
||||
)
|
||||
|
||||
// NotDefinedError is returned when requested metadata is not defined.
|
||||
@@ -99,73 +92,16 @@ func (suffix NotDefinedError) Error() string {
|
||||
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
||||
}
|
||||
|
||||
// Get returns a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
//
|
||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||
// 169.254.169.254 will be used instead.
|
||||
//
|
||||
// If the requested metadata is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
func Get(suffix string) (string, error) {
|
||||
val, _, err := getETag(metaClient, suffix)
|
||||
return val, err
|
||||
}
|
||||
|
||||
// getETag returns a value from the metadata service as well as the associated
|
||||
// ETag using the provided client. This func is otherwise equivalent to Get.
|
||||
func getETag(client *http.Client, suffix string) (value, etag string, err error) {
|
||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||
// a container, which is an important use-case for local testing of cloud
|
||||
// deployments. To enable spoofing of the metadata service, the environment
|
||||
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||
// requests shall go.
|
||||
host := os.Getenv(metadataHostEnv)
|
||||
if host == "" {
|
||||
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||
// binaries built with the "netgo" tag and without cgo won't
|
||||
// know the search suffix for "metadata" is
|
||||
// ".google.internal", and this IP address is documented as
|
||||
// being stable anyway.
|
||||
host = metadataIP
|
||||
}
|
||||
url := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Metadata-Flavor", "Google")
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return "", "", NotDefinedError(suffix)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
|
||||
}
|
||||
all, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return string(all), res.Header.Get("Etag"), nil
|
||||
}
|
||||
|
||||
func getTrimmed(suffix string) (s string, err error) {
|
||||
s, err = Get(suffix)
|
||||
s = strings.TrimSpace(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *cachedValue) get() (v string, err error) {
|
||||
func (c *cachedValue) get(cl *Client) (v string, err error) {
|
||||
defer c.mu.Unlock()
|
||||
c.mu.Lock()
|
||||
if c.v != "" {
|
||||
return c.v, nil
|
||||
}
|
||||
if c.trim {
|
||||
v, err = getTrimmed(c.k)
|
||||
v, err = cl.getTrimmed(c.k)
|
||||
} else {
|
||||
v, err = Get(c.k)
|
||||
v, err = cl.Get(c.k)
|
||||
}
|
||||
if err == nil {
|
||||
c.v = v
|
||||
@@ -200,9 +136,11 @@ func testOnGCE() bool {
|
||||
resc := make(chan bool, 2)
|
||||
|
||||
// Try two strategies in parallel.
|
||||
// See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194
|
||||
// See https://github.com/googleapis/google-cloud-go/issues/194
|
||||
go func() {
|
||||
res, err := ctxhttp.Get(ctx, metaClient, "http://"+metadataIP)
|
||||
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
res, err := defaultClient.hc.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
resc <- false
|
||||
return
|
||||
@@ -267,6 +205,267 @@ func systemInfoSuggestsGCE() bool {
|
||||
return name == "Google" || name == "Google Compute Engine"
|
||||
}
|
||||
|
||||
// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no
|
||||
// ResponseHeaderTimeout).
|
||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
return subscribeClient.Subscribe(suffix, fn)
|
||||
}
|
||||
|
||||
// Get calls Client.Get on the default client.
|
||||
func Get(suffix string) (string, error) { return defaultClient.Get(suffix) }
|
||||
|
||||
// ProjectID returns the current instance's project ID string.
|
||||
func ProjectID() (string, error) { return defaultClient.ProjectID() }
|
||||
|
||||
// NumericProjectID returns the current instance's numeric project ID.
|
||||
func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() }
|
||||
|
||||
// InternalIP returns the instance's primary internal IP address.
|
||||
func InternalIP() (string, error) { return defaultClient.InternalIP() }
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
|
||||
|
||||
// Email calls Client.Email on the default client.
|
||||
func Email(serviceAccount string) (string, error) { return defaultClient.Email(serviceAccount) }
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func Hostname() (string, error) { return defaultClient.Hostname() }
|
||||
|
||||
// InstanceTags returns the list of user-defined instance tags,
|
||||
// assigned when initially creating a GCE instance.
|
||||
func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() }
|
||||
|
||||
// InstanceID returns the current VM's numeric instance ID.
|
||||
func InstanceID() (string, error) { return defaultClient.InstanceID() }
|
||||
|
||||
// InstanceName returns the current VM's instance ID string.
|
||||
func InstanceName() (string, error) { return defaultClient.InstanceName() }
|
||||
|
||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||
func Zone() (string, error) { return defaultClient.Zone() }
|
||||
|
||||
// InstanceAttributes calls Client.InstanceAttributes on the default client.
|
||||
func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() }
|
||||
|
||||
// ProjectAttributes calls Client.ProjectAttributes on the default client.
|
||||
func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() }
|
||||
|
||||
// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client.
|
||||
func InstanceAttributeValue(attr string) (string, error) {
|
||||
return defaultClient.InstanceAttributeValue(attr)
|
||||
}
|
||||
|
||||
// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client.
|
||||
func ProjectAttributeValue(attr string) (string, error) {
|
||||
return defaultClient.ProjectAttributeValue(attr)
|
||||
}
|
||||
|
||||
// Scopes calls Client.Scopes on the default client.
|
||||
func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) }
|
||||
|
||||
func strsContains(ss []string, s string) bool {
|
||||
for _, v := range ss {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// A Client provides metadata.
|
||||
type Client struct {
|
||||
hc *http.Client
|
||||
}
|
||||
|
||||
// NewClient returns a Client that can be used to fetch metadata. All HTTP requests
|
||||
// will use the given http.Client instead of the default client.
|
||||
func NewClient(c *http.Client) *Client {
|
||||
return &Client{hc: c}
|
||||
}
|
||||
|
||||
// getETag returns a value from the metadata service as well as the associated ETag.
|
||||
// This func is otherwise equivalent to Get.
|
||||
func (c *Client) getETag(suffix string) (value, etag string, err error) {
|
||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||
// a container, which is an important use-case for local testing of cloud
|
||||
// deployments. To enable spoofing of the metadata service, the environment
|
||||
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||
// requests shall go.
|
||||
host := os.Getenv(metadataHostEnv)
|
||||
if host == "" {
|
||||
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||
// binaries built with the "netgo" tag and without cgo won't
|
||||
// know the search suffix for "metadata" is
|
||||
// ".google.internal", and this IP address is documented as
|
||||
// being stable anyway.
|
||||
host = metadataIP
|
||||
}
|
||||
u := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
req.Header.Set("Metadata-Flavor", "Google")
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
res, err := c.hc.Do(req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return "", "", NotDefinedError(suffix)
|
||||
}
|
||||
all, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return "", "", &Error{Code: res.StatusCode, Message: string(all)}
|
||||
}
|
||||
return string(all), res.Header.Get("Etag"), nil
|
||||
}
|
||||
|
||||
// Get returns a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
//
|
||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||
// 169.254.169.254 will be used instead.
|
||||
//
|
||||
// If the requested metadata is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
func (c *Client) Get(suffix string) (string, error) {
|
||||
val, _, err := c.getETag(suffix)
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (c *Client) getTrimmed(suffix string) (s string, err error) {
|
||||
s, err = c.Get(suffix)
|
||||
s = strings.TrimSpace(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) lines(suffix string) ([]string, error) {
|
||||
j, err := c.Get(suffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||
for i := range s {
|
||||
s[i] = strings.TrimSpace(s[i])
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// ProjectID returns the current instance's project ID string.
|
||||
func (c *Client) ProjectID() (string, error) { return projID.get(c) }
|
||||
|
||||
// NumericProjectID returns the current instance's numeric project ID.
|
||||
func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) }
|
||||
|
||||
// InstanceID returns the current VM's numeric instance ID.
|
||||
func (c *Client) InstanceID() (string, error) { return instID.get(c) }
|
||||
|
||||
// InternalIP returns the instance's primary internal IP address.
|
||||
func (c *Client) InternalIP() (string, error) {
|
||||
return c.getTrimmed("instance/network-interfaces/0/ip")
|
||||
}
|
||||
|
||||
// Email returns the email address associated with the service account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func (c *Client) Email(serviceAccount string) (string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return c.getTrimmed("instance/service-accounts/" + serviceAccount + "/email")
|
||||
}
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func (c *Client) ExternalIP() (string, error) {
|
||||
return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||
}
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func (c *Client) Hostname() (string, error) {
|
||||
return c.getTrimmed("instance/hostname")
|
||||
}
|
||||
|
||||
// InstanceTags returns the list of user-defined instance tags,
|
||||
// assigned when initially creating a GCE instance.
|
||||
func (c *Client) InstanceTags() ([]string, error) {
|
||||
var s []string
|
||||
j, err := c.Get("instance/tags")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceName returns the current VM's instance ID string.
|
||||
func (c *Client) InstanceName() (string, error) {
|
||||
return c.getTrimmed("instance/name")
|
||||
}
|
||||
|
||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||
func (c *Client) Zone() (string, error) {
|
||||
zone, err := c.getTrimmed("instance/zone")
|
||||
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||
}
|
||||
|
||||
// InstanceAttributes returns the list of user-defined attributes,
|
||||
// assigned when initially creating a GCE VM instance. The value of an
|
||||
// attribute can be obtained with InstanceAttributeValue.
|
||||
func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") }
|
||||
|
||||
// ProjectAttributes returns the list of user-defined attributes
|
||||
// applying to the project as a whole, not just this VM. The value of
|
||||
// an attribute can be obtained with ProjectAttributeValue.
|
||||
func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") }
|
||||
|
||||
// InstanceAttributeValue returns the value of the provided VM
|
||||
// instance attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
|
||||
return c.Get("instance/attributes/" + attr)
|
||||
}
|
||||
|
||||
// ProjectAttributeValue returns the value of the provided
|
||||
// project attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
|
||||
return c.Get("project/attributes/" + attr)
|
||||
}
|
||||
|
||||
// Scopes returns the service account scopes for the given account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return c.lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||
}
|
||||
|
||||
// Subscribe subscribes to a value from the metadata service.
|
||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||
// The suffix may contain query parameters.
|
||||
@@ -276,11 +475,11 @@ func systemInfoSuggestsGCE() bool {
|
||||
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
||||
// is deleted. Subscribe returns the error value returned from the last call to
|
||||
// fn, which may be nil when ok == false.
|
||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
const failedSubscribeSleep = time.Second * 5
|
||||
|
||||
// First check to see if the metadata value exists at all.
|
||||
val, lastETag, err := getETag(subscribeClient, suffix)
|
||||
val, lastETag, err := c.getETag(suffix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -296,7 +495,7 @@ func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
suffix += "?wait_for_change=true&last_etag="
|
||||
}
|
||||
for {
|
||||
val, etag, err := getETag(subscribeClient, suffix+url.QueryEscape(lastETag))
|
||||
val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
|
||||
if err != nil {
|
||||
if _, deleted := err.(NotDefinedError); !deleted {
|
||||
time.Sleep(failedSubscribeSleep)
|
||||
@@ -312,127 +511,14 @@ func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||
}
|
||||
}
|
||||
|
||||
// ProjectID returns the current instance's project ID string.
|
||||
func ProjectID() (string, error) { return projID.get() }
|
||||
|
||||
// NumericProjectID returns the current instance's numeric project ID.
|
||||
func NumericProjectID() (string, error) { return projNum.get() }
|
||||
|
||||
// InternalIP returns the instance's primary internal IP address.
|
||||
func InternalIP() (string, error) {
|
||||
return getTrimmed("instance/network-interfaces/0/ip")
|
||||
// Error contains an error response from the server.
|
||||
type Error struct {
|
||||
// Code is the HTTP response status code.
|
||||
Code int
|
||||
// Message is the server response message.
|
||||
Message string
|
||||
}
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func ExternalIP() (string, error) {
|
||||
return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||
}
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func Hostname() (string, error) {
|
||||
return getTrimmed("instance/hostname")
|
||||
}
|
||||
|
||||
// InstanceTags returns the list of user-defined instance tags,
|
||||
// assigned when initially creating a GCE instance.
|
||||
func InstanceTags() ([]string, error) {
|
||||
var s []string
|
||||
j, err := Get("instance/tags")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceID returns the current VM's numeric instance ID.
|
||||
func InstanceID() (string, error) {
|
||||
return instID.get()
|
||||
}
|
||||
|
||||
// InstanceName returns the current VM's instance ID string.
|
||||
func InstanceName() (string, error) {
|
||||
host, err := Hostname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.Split(host, ".")[0], nil
|
||||
}
|
||||
|
||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||
func Zone() (string, error) {
|
||||
zone, err := getTrimmed("instance/zone")
|
||||
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||
}
|
||||
|
||||
// InstanceAttributes returns the list of user-defined attributes,
|
||||
// assigned when initially creating a GCE VM instance. The value of an
|
||||
// attribute can be obtained with InstanceAttributeValue.
|
||||
func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }
|
||||
|
||||
// ProjectAttributes returns the list of user-defined attributes
|
||||
// applying to the project as a whole, not just this VM. The value of
|
||||
// an attribute can be obtained with ProjectAttributeValue.
|
||||
func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
|
||||
|
||||
func lines(suffix string) ([]string, error) {
|
||||
j, err := Get(suffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||
for i := range s {
|
||||
s[i] = strings.TrimSpace(s[i])
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstanceAttributeValue returns the value of the provided VM
|
||||
// instance attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func InstanceAttributeValue(attr string) (string, error) {
|
||||
return Get("instance/attributes/" + attr)
|
||||
}
|
||||
|
||||
// ProjectAttributeValue returns the value of the provided
|
||||
// project attribute.
|
||||
//
|
||||
// If the requested attribute is not defined, the returned error will
|
||||
// be of type NotDefinedError.
|
||||
//
|
||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||
// defined to be the empty string.
|
||||
func ProjectAttributeValue(attr string) (string, error) {
|
||||
return Get("project/attributes/" + attr)
|
||||
}
|
||||
|
||||
// Scopes returns the service account scopes for the given account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func Scopes(serviceAccount string) ([]string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||
}
|
||||
|
||||
func strsContains(ss []string, s string) bool {
|
||||
for _, v := range ss {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
|
||||
}
|
||||
|
||||
31
src/cmd/linuxkit/vendor/cloud.google.com/go/go.mod
generated
vendored
Normal file
31
src/cmd/linuxkit/vendor/cloud.google.com/go/go.mod
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
module cloud.google.com/go
|
||||
|
||||
go 1.11
|
||||
|
||||
require (
|
||||
cloud.google.com/go/bigquery v1.3.0
|
||||
cloud.google.com/go/datastore v1.0.0
|
||||
cloud.google.com/go/pubsub v1.1.0
|
||||
cloud.google.com/go/storage v1.5.0
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/mock v1.4.0
|
||||
github.com/golang/protobuf v1.3.3
|
||||
github.com/google/go-cmp v0.4.0
|
||||
github.com/google/martian v2.1.0+incompatible
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12
|
||||
github.com/googleapis/gax-go/v2 v2.0.5
|
||||
github.com/jstemmer/go-junit-report v0.9.1
|
||||
go.opencensus.io v0.22.3
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367
|
||||
golang.org/x/mod v0.2.0 // indirect
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56
|
||||
google.golang.org/api v0.17.0
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce
|
||||
google.golang.org/grpc v1.27.1
|
||||
honnef.co/go/tools v0.0.1-2019.2.3
|
||||
)
|
||||
64
src/cmd/linuxkit/vendor/cloud.google.com/go/internal/cloud.go
generated
vendored
64
src/cmd/linuxkit/vendor/cloud.google.com/go/internal/cloud.go
generated
vendored
@@ -1,64 +0,0 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package internal provides support for the cloud packages.
|
||||
//
|
||||
// Users should not import this package directly.
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const userAgent = "gcloud-golang/0.1"
|
||||
|
||||
// Transport is an http.RoundTripper that appends Google Cloud client's
|
||||
// user-agent to the original request's user-agent header.
|
||||
type Transport struct {
|
||||
// TODO(bradfitz): delete internal.Transport. It's too wrappy for what it does.
|
||||
// Do User-Agent some other way.
|
||||
|
||||
// Base is the actual http.RoundTripper
|
||||
// requests will use. It must not be nil.
|
||||
Base http.RoundTripper
|
||||
}
|
||||
|
||||
// RoundTrip appends a user-agent to the existing user-agent
|
||||
// header and delegates the request to the base http.RoundTripper.
|
||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = cloneRequest(req)
|
||||
ua := req.Header.Get("User-Agent")
|
||||
if ua == "" {
|
||||
ua = userAgent
|
||||
} else {
|
||||
ua = fmt.Sprintf("%s %s", ua, userAgent)
|
||||
}
|
||||
req.Header.Set("User-Agent", ua)
|
||||
return t.Base.RoundTrip(req)
|
||||
}
|
||||
|
||||
// cloneRequest returns a clone of the provided *http.Request.
|
||||
// The clone is a shallow copy of the struct and its Header map.
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
// shallow copy of the struct
|
||||
r2 := new(http.Request)
|
||||
*r2 = *r
|
||||
// deep copy of the Header
|
||||
r2.Header = make(http.Header)
|
||||
for k, s := range r.Header {
|
||||
r2.Header[k] = s
|
||||
}
|
||||
return r2
|
||||
}
|
||||
55
src/cmd/linuxkit/vendor/cloud.google.com/go/internal/retry.go
generated
vendored
55
src/cmd/linuxkit/vendor/cloud.google.com/go/internal/retry.go
generated
vendored
@@ -1,55 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
gax "github.com/googleapis/gax-go"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Retry calls the supplied function f repeatedly according to the provided
|
||||
// backoff parameters. It returns when one of the following occurs:
|
||||
// When f's first return value is true, Retry immediately returns with f's second
|
||||
// return value.
|
||||
// When the provided context is done, Retry returns with ctx.Err().
|
||||
func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error {
|
||||
return retry(ctx, bo, f, gax.Sleep)
|
||||
}
|
||||
|
||||
func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
|
||||
sleep func(context.Context, time.Duration) error) error {
|
||||
var lastErr error
|
||||
for {
|
||||
stop, err := f()
|
||||
if stop {
|
||||
return err
|
||||
}
|
||||
// Remember the last "real" error from f.
|
||||
if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
|
||||
lastErr = err
|
||||
}
|
||||
p := bo.Pause()
|
||||
if cerr := sleep(ctx, p); cerr != nil {
|
||||
if lastErr != nil {
|
||||
return fmt.Errorf("%v; last function err: %v", cerr, lastErr)
|
||||
}
|
||||
return cerr
|
||||
}
|
||||
}
|
||||
}
|
||||
202
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/LICENSE
generated
vendored
202
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/LICENSE
generated
vendored
@@ -1,202 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
11
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/README.md
generated
vendored
11
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/README.md
generated
vendored
@@ -1,11 +0,0 @@
|
||||
# p9p [](https://godoc.org/github.com/docker/go-p9p) [](https://raw.githubusercontent.com/docker/go-p9p/master/LICENSE) [](https://circleci.com/gh/docker/go-p9p) [](https://travis-ci.org/docker/go-p9p) [](https://goreportcard.com/report/github.com/docker/go-p9p) [](http://doyouevenbadge.com/report/github.com/docker/go-p9p)
|
||||
|
||||
|
||||
A modern, performant 9P library for Go.
|
||||
|
||||
For information on usage, please see the [GoDoc](https://godoc.org/github.com/docker/go-p9p).
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Copyright © 2015 Docker, Inc. go-p9p is licensed under the Apache License,
|
||||
Version 2.0. See [LICENSE](LICENSE) for the full license text.
|
||||
343
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/channel.go
generated
vendored
343
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/channel.go
generated
vendored
@@ -1,343 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// channelMessageHeaderSize is the overhead for sending the size of a
|
||||
// message on the wire.
|
||||
channelMessageHeaderSize = 4
|
||||
)
|
||||
|
||||
// Channel defines the operations necessary to implement a 9p message channel
|
||||
// interface. Typically, message channels do no protocol processing except to
|
||||
// send and receive message frames.
|
||||
type Channel interface {
|
||||
// ReadFcall reads one fcall frame into the provided fcall structure. The
|
||||
// Fcall may be cleared whether there is an error or not. If the operation
|
||||
// is successful, the contents of the fcall will be populated in the
|
||||
// argument. ReadFcall cannot be called concurrently with other calls to
|
||||
// ReadFcall. This both to preserve message ordering and to allow lockless
|
||||
// buffer reusage.
|
||||
ReadFcall(ctx context.Context, fcall *Fcall) error
|
||||
|
||||
// WriteFcall writes the provided fcall to the channel. WriteFcall cannot
|
||||
// be called concurrently with other calls to WriteFcall.
|
||||
WriteFcall(ctx context.Context, fcall *Fcall) error
|
||||
|
||||
// MSize returns the current msize for the channel.
|
||||
MSize() int
|
||||
|
||||
// SetMSize sets the maximum message size for the channel. This must never
|
||||
// be called currently with ReadFcall or WriteFcall.
|
||||
SetMSize(msize int)
|
||||
}
|
||||
|
||||
// NewChannel returns a new channel to read and write Fcalls with the provided
|
||||
// connection and message size.
|
||||
func NewChannel(conn net.Conn, msize int) Channel {
|
||||
return newChannel(conn, codec9p{}, msize)
|
||||
}
|
||||
|
||||
const (
|
||||
defaultRWTimeout = 30 * time.Second // default read/write timeout if not set in context
|
||||
)
|
||||
|
||||
// channel provides bidirectional protocol framing for 9p over net.Conn.
|
||||
// Operations are not thread-safe but reads and writes may be carried out
|
||||
// concurrently, supporting separate read and write loops.
|
||||
//
|
||||
// Lifecyle
|
||||
//
|
||||
// A connection, or message channel abstraction, has a lifecycle delineated by
|
||||
// Tversion/Rversion request response cycles. For now, this is part of the
|
||||
// channel itself but doesn't necessarily influence the channels state, except
|
||||
// the msize. Visually, it might look something like this:
|
||||
//
|
||||
// [Established] -> [Version] -> [Session] -> [Version]---+
|
||||
// ^ |
|
||||
// |_________________________________|
|
||||
//
|
||||
// The connection is established, then we negotiate a version, run a session,
|
||||
// then negotiate a version and so on. For most purposes, we are likely going
|
||||
// to terminate the connection after the session but we may want to support
|
||||
// connection pooling. Pooling may result in possible security leaks if the
|
||||
// connections are shared among contexts, since the version is negotiated at
|
||||
// the start of the session. To avoid this, we can actually use a "tombstone"
|
||||
// version message which clears the server's session state without starting a
|
||||
// new session. The next version message would then prepare the session
|
||||
// without leaking any Fid's.
|
||||
type channel struct {
|
||||
conn net.Conn
|
||||
codec Codec
|
||||
brd *bufio.Reader
|
||||
bwr *bufio.Writer
|
||||
closed chan struct{}
|
||||
msize int
|
||||
rdbuf []byte
|
||||
}
|
||||
|
||||
func newChannel(conn net.Conn, codec Codec, msize int) *channel {
|
||||
return &channel{
|
||||
conn: conn,
|
||||
codec: codec,
|
||||
brd: bufio.NewReaderSize(conn, msize), // msize may not be optimal buffer size
|
||||
bwr: bufio.NewWriterSize(conn, msize),
|
||||
closed: make(chan struct{}),
|
||||
msize: msize,
|
||||
rdbuf: make([]byte, msize),
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *channel) MSize() int {
|
||||
return ch.msize
|
||||
}
|
||||
|
||||
// setmsize resizes the buffers for use with a separate msize. This call must
|
||||
// be protected by a mutex or made before passing to other goroutines.
|
||||
func (ch *channel) SetMSize(msize int) {
|
||||
// NOTE(stevvooe): We cannot safely resize the buffered reader and writer.
|
||||
// Proceed assuming that original size is sufficient.
|
||||
|
||||
ch.msize = msize
|
||||
if msize < len(ch.rdbuf) {
|
||||
// just change the cap
|
||||
ch.rdbuf = ch.rdbuf[:msize]
|
||||
return
|
||||
}
|
||||
|
||||
ch.rdbuf = make([]byte, msize)
|
||||
}
|
||||
|
||||
// ReadFcall reads the next message from the channel into fcall.
|
||||
//
|
||||
// If the incoming message overflows the msize, Overflow(err) will return
|
||||
// nonzero with the number of bytes overflowed.
|
||||
func (ch *channel) ReadFcall(ctx context.Context, fcall *Fcall) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ch.closed:
|
||||
return ErrClosed
|
||||
default:
|
||||
}
|
||||
|
||||
deadline, ok := ctx.Deadline()
|
||||
if !ok {
|
||||
deadline = time.Now().Add(defaultRWTimeout)
|
||||
}
|
||||
|
||||
if err := ch.conn.SetReadDeadline(deadline); err != nil {
|
||||
log.Printf("transport: error setting read deadline on %v: %v", ch.conn.RemoteAddr(), err)
|
||||
}
|
||||
|
||||
n, err := readmsg(ch.brd, ch.rdbuf)
|
||||
if err != nil {
|
||||
// TODO(stevvooe): There may be more we can do here to detect partial
|
||||
// reads. For now, we just propagate the error untouched.
|
||||
return err
|
||||
}
|
||||
|
||||
if n > len(ch.rdbuf) {
|
||||
return overflowErr{size: n - len(ch.rdbuf)}
|
||||
}
|
||||
|
||||
// clear out the fcall
|
||||
*fcall = Fcall{}
|
||||
if err := ch.codec.Unmarshal(ch.rdbuf[:n], fcall); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ch.maybeTruncate(fcall); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteFcall writes the message to the connection.
|
||||
//
|
||||
// If a message destined for the wire will overflow MSize, an Overflow error
|
||||
// may be returned. For Twrite calls, the buffer will simply be truncated to
|
||||
// the optimal msize, with the caller detecting this condition with
|
||||
// Rwrite.Count.
|
||||
func (ch *channel) WriteFcall(ctx context.Context, fcall *Fcall) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ch.closed:
|
||||
return ErrClosed
|
||||
default:
|
||||
}
|
||||
|
||||
deadline, ok := ctx.Deadline()
|
||||
if !ok {
|
||||
deadline = time.Now().Add(defaultRWTimeout)
|
||||
}
|
||||
|
||||
if err := ch.conn.SetWriteDeadline(deadline); err != nil {
|
||||
log.Printf("transport: error setting read deadline on %v: %v", ch.conn.RemoteAddr(), err)
|
||||
}
|
||||
|
||||
if err := ch.maybeTruncate(fcall); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p, err := ch.codec.Marshal(fcall)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sendmsg(ch.bwr, p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ch.bwr.Flush()
|
||||
}
|
||||
|
||||
// maybeTruncate will truncate the message to fit into msize on the wire, if
|
||||
// possible, or modify the message to ensure the response won't overflow.
|
||||
//
|
||||
// If the message cannot be truncated, an error will be returned and the
|
||||
// message should not be sent.
|
||||
//
|
||||
// A nil return value means the message can be sent without
|
||||
func (ch *channel) maybeTruncate(fcall *Fcall) error {
|
||||
|
||||
// for certain message types, just remove the extra bytes from the data portion.
|
||||
switch msg := fcall.Message.(type) {
|
||||
// TODO(stevvooe): There is one more problematic message type:
|
||||
//
|
||||
// Rread: while we can employ the same truncation fix as Twrite, we
|
||||
// need to make it observable to upstream handlers.
|
||||
|
||||
case MessageTread:
|
||||
// We can rewrite msg.Count so that a return message will be under
|
||||
// msize. This is more defensive than anything but will ensure that
|
||||
// calls don't fail on sloppy servers.
|
||||
|
||||
// first, craft the shape of the response message
|
||||
resp := newFcall(fcall.Tag, MessageRread{})
|
||||
overflow := uint32(ch.msgmsize(resp)) + msg.Count - uint32(ch.msize)
|
||||
|
||||
if msg.Count < overflow {
|
||||
// Let the bad thing happen; msize too small to even support valid
|
||||
// rewrite. This will result in a Terror from the server-side or
|
||||
// just work.
|
||||
return nil
|
||||
}
|
||||
|
||||
msg.Count -= overflow
|
||||
fcall.Message = msg
|
||||
|
||||
return nil
|
||||
case MessageTwrite:
|
||||
// If we are going to overflow the msize, we need to truncate the write to
|
||||
// appropriate size or throw an error in all other conditions.
|
||||
size := ch.msgmsize(fcall)
|
||||
if size <= ch.msize {
|
||||
return nil
|
||||
}
|
||||
|
||||
// overflow the msize, including the channel message size fields.
|
||||
overflow := size - ch.msize
|
||||
|
||||
if len(msg.Data) < overflow {
|
||||
// paranoid: if msg.Data is not big enough to handle the
|
||||
// overflow, we should get an overflow error. MSize would have
|
||||
// to be way too small to be realistic.
|
||||
return overflowErr{size: overflow}
|
||||
}
|
||||
|
||||
// The truncation is reflected in the return message (Rwrite) by
|
||||
// the server, so we don't need a return value or error condition
|
||||
// to communicate it.
|
||||
msg.Data = msg.Data[:len(msg.Data)-overflow]
|
||||
fcall.Message = msg // since we have a local copy
|
||||
|
||||
return nil
|
||||
default:
|
||||
size := ch.msgmsize(fcall)
|
||||
if size > ch.msize {
|
||||
// overflow the msize, including the channel message size fields.
|
||||
return overflowErr{size: size - ch.msize}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// msgmsize returns the on-wire msize of the Fcall, including the size header.
|
||||
// Typically, this can be used to detect whether or not the message overflows
|
||||
// the msize buffer.
|
||||
func (ch *channel) msgmsize(fcall *Fcall) int {
|
||||
return channelMessageHeaderSize + ch.codec.Size(fcall)
|
||||
}
|
||||
|
||||
// readmsg reads a 9p message into p from rd, ensuring that all bytes are
|
||||
// consumed from the size header. If the size header indicates the message is
|
||||
// larger than p, the entire message will be discarded, leaving a truncated
|
||||
// portion in p. Any error should be treated as a framing error unless n is
|
||||
// zero. The caller must check that n is less than or equal to len(p) to
|
||||
// ensure that a valid message has been read.
|
||||
func readmsg(rd io.Reader, p []byte) (n int, err error) {
|
||||
var msize uint32
|
||||
|
||||
if err := binary.Read(rd, binary.LittleEndian, &msize); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
n += binary.Size(msize)
|
||||
mbody := int(msize) - 4
|
||||
|
||||
if mbody < len(p) {
|
||||
p = p[:mbody]
|
||||
}
|
||||
|
||||
np, err := io.ReadFull(rd, p)
|
||||
if err != nil {
|
||||
return np + n, err
|
||||
}
|
||||
n += np
|
||||
|
||||
if mbody > len(p) {
|
||||
// message has been read up to len(p) but we must consume the entire
|
||||
// message. This is an error condition but is non-fatal if we can
|
||||
// consume msize bytes.
|
||||
nn, err := io.CopyN(ioutil.Discard, rd, int64(mbody-len(p)))
|
||||
n += int(nn)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// sendmsg writes a message of len(p) to wr with a 9p size header. All errors
|
||||
// should be considered terminal.
|
||||
func sendmsg(wr io.Writer, p []byte) error {
|
||||
size := uint32(len(p) + 4) // message size plus 4-bytes for size.
|
||||
if err := binary.Write(wr, binary.LittleEndian, size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This assume partial writes to wr aren't possible. Not sure if this
|
||||
// valid. Matters during timeout retries.
|
||||
if n, err := wr.Write(p); err != nil {
|
||||
return err
|
||||
} else if n < len(p) {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
253
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/client.go
generated
vendored
253
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/client.go
generated
vendored
@@ -1,253 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"context"
|
||||
)
|
||||
|
||||
type client struct {
|
||||
version string
|
||||
msize int
|
||||
ctx context.Context
|
||||
transport roundTripper
|
||||
}
|
||||
|
||||
// NewSession returns a session using the connection. The Context ctx provides
|
||||
// a context for out of bad messages, such as flushes, that may be sent by the
|
||||
// session. The session can effectively shutdown with this context.
|
||||
func NewSession(ctx context.Context, conn net.Conn) (Session, error) {
|
||||
ch := newChannel(conn, codec9p{}, DefaultMSize) // sets msize, effectively.
|
||||
|
||||
// negotiate the protocol version
|
||||
version, err := clientnegotiate(ctx, ch, DefaultVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &client{
|
||||
version: version,
|
||||
msize: ch.MSize(),
|
||||
ctx: ctx,
|
||||
transport: newTransport(ctx, ch),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ Session = &client{}
|
||||
|
||||
func (c *client) Version() (int, string) {
|
||||
return c.msize, c.version
|
||||
}
|
||||
|
||||
func (c *client) Auth(ctx context.Context, afid Fid, uname, aname string) (Qid, error) {
|
||||
m := MessageTauth{
|
||||
Afid: afid,
|
||||
Uname: uname,
|
||||
Aname: aname,
|
||||
}
|
||||
|
||||
resp, err := c.transport.send(ctx, m)
|
||||
if err != nil {
|
||||
return Qid{}, err
|
||||
}
|
||||
|
||||
rauth, ok := resp.(MessageRauth)
|
||||
if !ok {
|
||||
return Qid{}, ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return rauth.Qid, nil
|
||||
}
|
||||
|
||||
func (c *client) Attach(ctx context.Context, fid, afid Fid, uname, aname string) (Qid, error) {
|
||||
m := MessageTattach{
|
||||
Fid: fid,
|
||||
Afid: afid,
|
||||
Uname: uname,
|
||||
Aname: aname,
|
||||
}
|
||||
|
||||
resp, err := c.transport.send(ctx, m)
|
||||
if err != nil {
|
||||
return Qid{}, err
|
||||
}
|
||||
|
||||
rattach, ok := resp.(MessageRattach)
|
||||
if !ok {
|
||||
return Qid{}, ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return rattach.Qid, nil
|
||||
}
|
||||
|
||||
func (c *client) Clunk(ctx context.Context, fid Fid) error {
|
||||
resp, err := c.transport.send(ctx, MessageTclunk{
|
||||
Fid: fid,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, ok := resp.(MessageRclunk)
|
||||
if !ok {
|
||||
return ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) Remove(ctx context.Context, fid Fid) error {
|
||||
resp, err := c.transport.send(ctx, MessageTremove{
|
||||
Fid: fid,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, ok := resp.(MessageRremove)
|
||||
if !ok {
|
||||
return ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) Walk(ctx context.Context, fid Fid, newfid Fid, names ...string) ([]Qid, error) {
|
||||
if len(names) > 16 {
|
||||
return nil, ErrWalkLimit
|
||||
}
|
||||
|
||||
resp, err := c.transport.send(ctx, MessageTwalk{
|
||||
Fid: fid,
|
||||
Newfid: newfid,
|
||||
Wnames: names,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rwalk, ok := resp.(MessageRwalk)
|
||||
if !ok {
|
||||
return nil, ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return rwalk.Qids, nil
|
||||
}
|
||||
|
||||
func (c *client) Read(ctx context.Context, fid Fid, p []byte, offset int64) (n int, err error) {
|
||||
resp, err := c.transport.send(ctx, MessageTread{
|
||||
Fid: fid,
|
||||
Offset: uint64(offset),
|
||||
Count: uint32(len(p)),
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
rread, ok := resp.(MessageRread)
|
||||
if !ok {
|
||||
return 0, ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
n = copy(p, rread.Data)
|
||||
switch {
|
||||
case len(rread.Data) == 0:
|
||||
err = io.EOF
|
||||
case n < len(p):
|
||||
// TODO(stevvooe): Technically, we should treat this as an io.EOF.
|
||||
// However, we cannot tell if the short read was due to EOF or due to
|
||||
// truncation.
|
||||
}
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *client) Write(ctx context.Context, fid Fid, p []byte, offset int64) (n int, err error) {
|
||||
resp, err := c.transport.send(ctx, MessageTwrite{
|
||||
Fid: fid,
|
||||
Offset: uint64(offset),
|
||||
Data: p,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
rwrite, ok := resp.(MessageRwrite)
|
||||
if !ok {
|
||||
return 0, ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
if int(rwrite.Count) < len(p) {
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
|
||||
return int(rwrite.Count), err
|
||||
}
|
||||
|
||||
func (c *client) Open(ctx context.Context, fid Fid, mode Flag) (Qid, uint32, error) {
|
||||
resp, err := c.transport.send(ctx, MessageTopen{
|
||||
Fid: fid,
|
||||
Mode: mode,
|
||||
})
|
||||
if err != nil {
|
||||
return Qid{}, 0, err
|
||||
}
|
||||
|
||||
ropen, ok := resp.(MessageRopen)
|
||||
if !ok {
|
||||
return Qid{}, 0, ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return ropen.Qid, ropen.IOUnit, nil
|
||||
}
|
||||
|
||||
func (c *client) Create(ctx context.Context, parent Fid, name string, perm uint32, mode Flag) (Qid, uint32, error) {
|
||||
resp, err := c.transport.send(ctx, MessageTcreate{
|
||||
Fid: parent,
|
||||
Name: name,
|
||||
Perm: perm,
|
||||
Mode: mode,
|
||||
})
|
||||
if err != nil {
|
||||
return Qid{}, 0, err
|
||||
}
|
||||
|
||||
rcreate, ok := resp.(MessageRcreate)
|
||||
if !ok {
|
||||
return Qid{}, 0, ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return rcreate.Qid, rcreate.IOUnit, nil
|
||||
}
|
||||
|
||||
func (c *client) Stat(ctx context.Context, fid Fid) (Dir, error) {
|
||||
resp, err := c.transport.send(ctx, MessageTstat{Fid: fid})
|
||||
if err != nil {
|
||||
return Dir{}, err
|
||||
}
|
||||
|
||||
rstat, ok := resp.(MessageRstat)
|
||||
if !ok {
|
||||
return Dir{}, ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return rstat.Stat, nil
|
||||
}
|
||||
|
||||
func (c *client) WStat(ctx context.Context, fid Fid, dir Dir) error {
|
||||
resp, err := c.transport.send(ctx, MessageTwstat{
|
||||
Fid: fid,
|
||||
Stat: dir,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, ok := resp.(MessageRwstat)
|
||||
if !ok {
|
||||
return ErrUnexpectedMsg
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
26
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/context.go
generated
vendored
26
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/context.go
generated
vendored
@@ -1,26 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const (
|
||||
versionKey contextKey = "9p.version"
|
||||
)
|
||||
|
||||
func withVersion(ctx context.Context, version string) context.Context {
|
||||
return context.WithValue(ctx, versionKey, version)
|
||||
}
|
||||
|
||||
// GetVersion returns the protocol version from the context. If the version is
|
||||
// not known, an empty string is returned. This is typically set on the
|
||||
// context passed into function calls in a server implementation.
|
||||
func GetVersion(ctx context.Context) string {
|
||||
v, ok := ctx.Value(versionKey).(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return v
|
||||
}
|
||||
133
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/dispatcher.go
generated
vendored
133
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/dispatcher.go
generated
vendored
@@ -1,133 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import "context"
|
||||
|
||||
// Handler defines an interface for 9p message handlers. A handler
|
||||
// implementation could be used to intercept calls of all types before sending
|
||||
// them to the next handler.
|
||||
type Handler interface {
|
||||
Handle(ctx context.Context, msg Message) (Message, error)
|
||||
|
||||
// TODO(stevvooe): Right now, this interface is functianally identical to
|
||||
// roundtripper. If we find that this is sufficient on the server-side, we
|
||||
// may unify the types. For now, we leave them separated to differentiate
|
||||
// between them.
|
||||
}
|
||||
|
||||
// HandlerFunc is a convenience type for defining inline handlers.
|
||||
type HandlerFunc func(ctx context.Context, msg Message) (Message, error)
|
||||
|
||||
// Handle implements the requirements for the Handler interface.
|
||||
func (fn HandlerFunc) Handle(ctx context.Context, msg Message) (Message, error) {
|
||||
return fn(ctx, msg)
|
||||
}
|
||||
|
||||
// Dispatch returns a handler that dispatches messages to the target session.
|
||||
// No concurrency is managed by the returned handler. It simply turns messages
|
||||
// into function calls on the session.
|
||||
func Dispatch(session Session) Handler {
|
||||
return HandlerFunc(func(ctx context.Context, msg Message) (Message, error) {
|
||||
switch msg := msg.(type) {
|
||||
case MessageTauth:
|
||||
qid, err := session.Auth(ctx, msg.Afid, msg.Uname, msg.Aname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRauth{Qid: qid}, nil
|
||||
case MessageTattach:
|
||||
qid, err := session.Attach(ctx, msg.Fid, msg.Afid, msg.Uname, msg.Aname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRattach{
|
||||
Qid: qid,
|
||||
}, nil
|
||||
case MessageTwalk:
|
||||
// TODO(stevvooe): This is one of the places where we need to manage
|
||||
// fid allocation lifecycle. We need to reserve the fid, then, if this
|
||||
// call succeeds, we should alloc the fid for future uses. Also need
|
||||
// to interact correctly with concurrent clunk and the flush of this
|
||||
// walk message.
|
||||
qids, err := session.Walk(ctx, msg.Fid, msg.Newfid, msg.Wnames...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRwalk{
|
||||
Qids: qids,
|
||||
}, nil
|
||||
case MessageTopen:
|
||||
qid, iounit, err := session.Open(ctx, msg.Fid, msg.Mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRopen{
|
||||
Qid: qid,
|
||||
IOUnit: iounit,
|
||||
}, nil
|
||||
case MessageTcreate:
|
||||
qid, iounit, err := session.Create(ctx, msg.Fid, msg.Name, msg.Perm, msg.Mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRcreate{
|
||||
Qid: qid,
|
||||
IOUnit: iounit,
|
||||
}, nil
|
||||
case MessageTread:
|
||||
p := make([]byte, int(msg.Count))
|
||||
n, err := session.Read(ctx, msg.Fid, p, int64(msg.Offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRread{
|
||||
Data: p[:n],
|
||||
}, nil
|
||||
case MessageTwrite:
|
||||
n, err := session.Write(ctx, msg.Fid, msg.Data, int64(msg.Offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRwrite{
|
||||
Count: uint32(n),
|
||||
}, nil
|
||||
case MessageTclunk:
|
||||
// TODO(stevvooe): Manage the clunking of file descriptors based on
|
||||
// walk and attach call progression.
|
||||
if err := session.Clunk(ctx, msg.Fid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRclunk{}, nil
|
||||
case MessageTremove:
|
||||
if err := session.Remove(ctx, msg.Fid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRremove{}, nil
|
||||
case MessageTstat:
|
||||
dir, err := session.Stat(ctx, msg.Fid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRstat{
|
||||
Stat: dir,
|
||||
}, nil
|
||||
case MessageTwstat:
|
||||
if err := session.WStat(ctx, msg.Fid, msg.Stat); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MessageRwstat{}, nil
|
||||
default:
|
||||
return nil, ErrUnknownMsg
|
||||
}
|
||||
})
|
||||
}
|
||||
78
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/doc.go
generated
vendored
78
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/doc.go
generated
vendored
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
Package p9p implements a compliant 9P2000 client and server library for use
|
||||
in modern, production Go services. This package differentiates itself in that
|
||||
is has departed from the plan 9 implementation primitives and better follows
|
||||
idiomatic Go style.
|
||||
|
||||
The package revolves around the session type, which is an enumeration of raw
|
||||
9p message calls. A few calls, such as flush and version, have been elided,
|
||||
defering their usage to the server implementation. Sessions can be trivially
|
||||
proxied through clients and servers.
|
||||
|
||||
Getting Started
|
||||
|
||||
The best place to get started is with Serve. Serve can be provided a
|
||||
connection and a handler. A typical implementation will call Serve as part of
|
||||
a listen/accept loop. As each network connection is created, Serve can be
|
||||
called with a handler for the specific connection. The handler can be
|
||||
implemented with a Session via the Dispatch function or can generate sessions
|
||||
for dispatch in response to client messages. (See cmd/9ps for an example)
|
||||
|
||||
On the client side, NewSession provides a 9p session from a connection. After
|
||||
a version negotiation, methods can be called on the session, in parallel, and
|
||||
calls will be sent over the connection. Call timeouts can be controlled via
|
||||
the context provided to each method call.
|
||||
|
||||
Framework
|
||||
|
||||
This package has the beginning of a nice client-server framework for working
|
||||
with 9p. Some of the abstractions aren't entirely fleshed out, but most of
|
||||
this can center around the Handler.
|
||||
|
||||
Missing from this are a number of tools for implementing 9p servers. The most
|
||||
glaring are directory read and walk helpers. Other, more complex additions
|
||||
might be a system to manage in memory filesystem trees that expose multi-user
|
||||
sessions.
|
||||
|
||||
Differences
|
||||
|
||||
The largest difference between this package and other 9p packages is
|
||||
simplification of the types needed to implement a server. To avoid confusing
|
||||
bugs and odd behavior, the components are separated by each level of the
|
||||
protocol. One example is that requests and responses are separated and they no
|
||||
longer hold mutable state. This means that framing, transport management,
|
||||
encoding, and dispatching are componentized. Little work will be required to
|
||||
swap out encodings, transports or connection implementations.
|
||||
|
||||
Context Integration
|
||||
|
||||
This package has been wired from top to bottom to support context-based
|
||||
resource management. Everything from startup to shutdown can have timeouts
|
||||
using contexts. Not all close methods are fully in place, but we are very
|
||||
close to having controlled, predictable cleanup for both servers and clients.
|
||||
Timeouts can be very granular or very course, depending on the context of the
|
||||
timeout. For example, it is very easy to set a short timeout for a stat call
|
||||
but a long timeout for reading data.
|
||||
|
||||
Multiversion Support
|
||||
|
||||
Currently, there is not multiversion support. The hooks and functionality are
|
||||
in place to add multi-version support. Generally, the correct space to do this
|
||||
is in the codec. Types, such as Dir, simply need to be extended to support the
|
||||
possibility of extra fields.
|
||||
|
||||
The real question to ask here is what is the role of the version number in the
|
||||
9p protocol. It really comes down to the level of support required. Do we just
|
||||
need it at the protocol level, or do handlers and sessions need to be have
|
||||
differently based on negotiated versions?
|
||||
|
||||
Caveats
|
||||
|
||||
This package has a number of TODOs to make it easier to use. Most of the
|
||||
existing code provides a solid base to work from. Don't be discouraged by the
|
||||
sawdust.
|
||||
|
||||
In addition, the testing is embarassingly lacking. With time, we can get full
|
||||
testing going and ensure we have confidence in the implementation.
|
||||
*/
|
||||
package p9p
|
||||
564
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/encoding.go
generated
vendored
564
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/encoding.go
generated
vendored
@@ -1,564 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Codec defines the interface for encoding and decoding of 9p types.
|
||||
// Unsupported types will throw an error.
|
||||
type Codec interface {
|
||||
// Unmarshal from data into the value pointed to by v.
|
||||
Unmarshal(data []byte, v interface{}) error
|
||||
|
||||
// Marshal the value v into a byte slice.
|
||||
Marshal(v interface{}) ([]byte, error)
|
||||
|
||||
// Size returns the encoded size for the target of v.
|
||||
Size(v interface{}) int
|
||||
}
|
||||
|
||||
// NewCodec returns a new, standard 9P2000 codec, ready for use.
|
||||
func NewCodec() Codec {
|
||||
return codec9p{}
|
||||
}
|
||||
|
||||
type codec9p struct{}
|
||||
|
||||
func (c codec9p) Unmarshal(data []byte, v interface{}) error {
|
||||
dec := &decoder{bytes.NewReader(data)}
|
||||
return dec.decode(v)
|
||||
}
|
||||
|
||||
func (c codec9p) Marshal(v interface{}) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
enc := &encoder{&b}
|
||||
|
||||
if err := enc.encode(v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (c codec9p) Size(v interface{}) int {
|
||||
return int(size9p(v))
|
||||
}
|
||||
|
||||
// DecodeDir decodes a directory entry from rd using the provided codec.
|
||||
func DecodeDir(codec Codec, rd io.Reader, d *Dir) error {
|
||||
var ll uint16
|
||||
|
||||
// pull the size off the wire
|
||||
if err := binary.Read(rd, binary.LittleEndian, &ll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := make([]byte, ll+2)
|
||||
binary.LittleEndian.PutUint16(p, ll) // must have size at start
|
||||
|
||||
// read out the rest of the record
|
||||
if _, err := io.ReadFull(rd, p[2:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return codec.Unmarshal(p, d)
|
||||
}
|
||||
|
||||
// EncodeDir writes the directory to wr.
|
||||
func EncodeDir(codec Codec, wr io.Writer, d *Dir) error {
|
||||
p, err := codec.Marshal(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = wr.Write(p)
|
||||
return err
|
||||
}
|
||||
|
||||
type encoder struct {
|
||||
wr io.Writer
|
||||
}
|
||||
|
||||
func (e *encoder) encode(vs ...interface{}) error {
|
||||
for _, v := range vs {
|
||||
switch v := v.(type) {
|
||||
case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
|
||||
*uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
|
||||
if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
|
||||
return err
|
||||
}
|
||||
case []byte:
|
||||
if err := e.encode(uint32(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *[]byte:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
case string:
|
||||
if err := binary.Write(e.wr, binary.LittleEndian, uint16(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := io.WriteString(e.wr, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *string:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case []string:
|
||||
if err := e.encode(uint16(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, m := range v {
|
||||
if err := e.encode(m); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case *[]string:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
case time.Time:
|
||||
if err := e.encode(uint32(v.Unix())); err != nil {
|
||||
return err
|
||||
}
|
||||
case *time.Time:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
case Qid:
|
||||
if err := e.encode(v.Type, v.Version, v.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Qid:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
case []Qid:
|
||||
if err := e.encode(uint16(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
elements := make([]interface{}, len(v))
|
||||
for i := range v {
|
||||
elements[i] = &v[i]
|
||||
}
|
||||
|
||||
if err := e.encode(elements...); err != nil {
|
||||
return err
|
||||
}
|
||||
case *[]Qid:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
case Dir:
|
||||
elements, err := fields9p(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.encode(uint16(size9p(elements...))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.encode(elements...); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Dir:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
case []Dir:
|
||||
elements := make([]interface{}, len(v))
|
||||
for i := range v {
|
||||
elements[i] = &v[i]
|
||||
}
|
||||
|
||||
if err := e.encode(elements...); err != nil {
|
||||
return err
|
||||
}
|
||||
case *[]Dir:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
case Fcall:
|
||||
if err := e.encode(v.Type, v.Tag, v.Message); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Fcall:
|
||||
if err := e.encode(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
case Message:
|
||||
elements, err := fields9p(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch v.(type) {
|
||||
case MessageRstat, *MessageRstat:
|
||||
// NOTE(stevvooe): Prepend size preceeding Dir. See bugs in
|
||||
// http://man.cat-v.org/plan_9/5/stat to make sense of this.
|
||||
// The field has been included here but we need to make sure
|
||||
// to double emit it for Rstat.
|
||||
if err := e.encode(uint16(size9p(elements...))); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := e.encode(elements...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type decoder struct {
|
||||
rd io.Reader
|
||||
}
|
||||
|
||||
// read9p extracts values from rd and unmarshals them to the targets of vs.
|
||||
func (d *decoder) decode(vs ...interface{}) error {
|
||||
for _, v := range vs {
|
||||
switch v := v.(type) {
|
||||
case *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
|
||||
if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
|
||||
return err
|
||||
}
|
||||
case *[]byte:
|
||||
var ll uint32
|
||||
|
||||
if err := d.decode(&ll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ll > 0 {
|
||||
*v = make([]byte, int(ll))
|
||||
}
|
||||
|
||||
if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
|
||||
return err
|
||||
}
|
||||
case *string:
|
||||
var ll uint16
|
||||
|
||||
// implement string[s] encoding
|
||||
if err := d.decode(&ll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := make([]byte, ll)
|
||||
|
||||
n, err := io.ReadFull(d.rd, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n != int(ll) {
|
||||
return fmt.Errorf("unexpected string length")
|
||||
}
|
||||
|
||||
*v = string(b)
|
||||
case *[]string:
|
||||
var ll uint16
|
||||
|
||||
if err := d.decode(&ll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
elements := make([]interface{}, int(ll))
|
||||
*v = make([]string, int(ll))
|
||||
for i := range elements {
|
||||
elements[i] = &(*v)[i]
|
||||
}
|
||||
|
||||
if err := d.decode(elements...); err != nil {
|
||||
return err
|
||||
}
|
||||
case *time.Time:
|
||||
var epoch uint32
|
||||
if err := d.decode(&epoch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = time.Unix(int64(epoch), 0).UTC()
|
||||
case *Qid:
|
||||
if err := d.decode(&v.Type, &v.Version, &v.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
case *[]Qid:
|
||||
var ll uint16
|
||||
|
||||
if err := d.decode(&ll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
elements := make([]interface{}, int(ll))
|
||||
*v = make([]Qid, int(ll))
|
||||
for i := range elements {
|
||||
elements[i] = &(*v)[i]
|
||||
}
|
||||
|
||||
if err := d.decode(elements...); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Dir:
|
||||
var ll uint16
|
||||
|
||||
if err := d.decode(&ll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := make([]byte, ll)
|
||||
// must consume entire dir entry.
|
||||
n, err := io.ReadFull(d.rd, b)
|
||||
if err != nil {
|
||||
log.Println("dir readfull failed:", err, ll, n)
|
||||
return err
|
||||
}
|
||||
|
||||
elements, err := fields9p(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dec := &decoder{bytes.NewReader(b)}
|
||||
|
||||
if err := dec.decode(elements...); err != nil {
|
||||
return err
|
||||
}
|
||||
case *[]Dir:
|
||||
*v = make([]Dir, 0)
|
||||
for {
|
||||
element := Dir{}
|
||||
if err := d.decode(&element); err != nil {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
*v = append(*v, element)
|
||||
}
|
||||
case *Fcall:
|
||||
if err := d.decode(&v.Type, &v.Tag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
message, err := newMessage(v.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// NOTE(stevvooe): We do a little pointer dance to allocate the
|
||||
// new type, write to it, then assign it back to the interface as
|
||||
// a concrete type, avoiding a pointer (the interface) to a
|
||||
// pointer.
|
||||
rv := reflect.New(reflect.TypeOf(message))
|
||||
if err := d.decode(rv.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.Message = rv.Elem().Interface().(Message)
|
||||
case Message:
|
||||
elements, err := fields9p(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch v.(type) {
|
||||
case *MessageRstat, MessageRstat:
|
||||
// NOTE(stevvooe): Consume extra size preceeding Dir. See bugs
|
||||
// in http://man.cat-v.org/plan_9/5/stat to make sense of
|
||||
// this. The field has been included here but we need to make
|
||||
// sure to double emit it for Rstat. decode extra size header
|
||||
// for stat structure.
|
||||
var ll uint16
|
||||
if err := d.decode(&ll); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := d.decode(elements...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// size9p calculates the projected size of the values in vs when encoded into
|
||||
// 9p binary protocol. If an element or elements are not valid for 9p encoded,
|
||||
// the value 0 will be used for the size. The error will be detected when
|
||||
// encoding.
|
||||
func size9p(vs ...interface{}) uint32 {
|
||||
var s uint32
|
||||
for _, v := range vs {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
switch v := v.(type) {
|
||||
case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
|
||||
*uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
|
||||
s += uint32(binary.Size(v))
|
||||
case []byte:
|
||||
s += uint32(binary.Size(uint32(0)) + len(v))
|
||||
case *[]byte:
|
||||
s += size9p(uint32(0), *v)
|
||||
case string:
|
||||
s += uint32(binary.Size(uint16(0)) + len(v))
|
||||
case *string:
|
||||
s += size9p(*v)
|
||||
case []string:
|
||||
s += size9p(uint16(0))
|
||||
|
||||
for _, sv := range v {
|
||||
s += size9p(sv)
|
||||
}
|
||||
case *[]string:
|
||||
s += size9p(*v)
|
||||
case time.Time, *time.Time:
|
||||
// BUG(stevvooe): Y2038 is coming.
|
||||
s += size9p(uint32(0))
|
||||
case Qid:
|
||||
s += size9p(v.Type, v.Version, v.Path)
|
||||
case *Qid:
|
||||
s += size9p(*v)
|
||||
case []Qid:
|
||||
s += size9p(uint16(0))
|
||||
elements := make([]interface{}, len(v))
|
||||
for i := range elements {
|
||||
elements[i] = &v[i]
|
||||
}
|
||||
s += size9p(elements...)
|
||||
case *[]Qid:
|
||||
s += size9p(*v)
|
||||
|
||||
case Dir:
|
||||
// walk the fields of the message to get the total size. we just
|
||||
// use the field order from the message struct. We may add tag
|
||||
// ignoring if needed.
|
||||
elements, err := fields9p(v)
|
||||
if err != nil {
|
||||
// BUG(stevvooe): The options here are to return 0, panic or
|
||||
// make this return an error. Ideally, we make it safe to
|
||||
// return 0 and have the rest of the package do the right
|
||||
// thing. For now, we do this, but may want to panic until
|
||||
// things are stable.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s += size9p(elements...) + size9p(uint16(0))
|
||||
case *Dir:
|
||||
s += size9p(*v)
|
||||
case []Dir:
|
||||
elements := make([]interface{}, len(v))
|
||||
for i := range elements {
|
||||
elements[i] = &v[i]
|
||||
}
|
||||
s += size9p(elements...)
|
||||
case *[]Dir:
|
||||
s += size9p(*v)
|
||||
case Fcall:
|
||||
s += size9p(v.Type, v.Tag, v.Message)
|
||||
case *Fcall:
|
||||
s += size9p(*v)
|
||||
case Message:
|
||||
// special case twstat and rstat for size fields. See bugs in
|
||||
// http://man.cat-v.org/plan_9/5/stat to make sense of this.
|
||||
switch v.(type) {
|
||||
case *MessageRstat, MessageRstat:
|
||||
s += size9p(uint16(0)) // for extra size field before dir
|
||||
}
|
||||
|
||||
// walk the fields of the message to get the total size. we just
|
||||
// use the field order from the message struct. We may add tag
|
||||
// ignoring if needed.
|
||||
elements, err := fields9p(v)
|
||||
if err != nil {
|
||||
// BUG(stevvooe): The options here are to return 0, panic or
|
||||
// make this return an error. Ideally, we make it safe to
|
||||
// return 0 and have the rest of the package do the right
|
||||
// thing. For now, we do this, but may want to panic until
|
||||
// things are stable.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s += size9p(elements...)
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// fields9p lists the settable fields from a struct type for reading and
|
||||
// writing. We are using a lot of reflection here for fairly static
|
||||
// serialization but we can replace this in the future with generated code if
|
||||
// performance is an issue.
|
||||
func fields9p(v interface{}) ([]interface{}, error) {
|
||||
rv := reflect.Indirect(reflect.ValueOf(v))
|
||||
|
||||
if rv.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("cannot extract fields from non-struct: %v", rv)
|
||||
}
|
||||
|
||||
var elements []interface{}
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
f := rv.Field(i)
|
||||
|
||||
if !f.CanInterface() {
|
||||
// unexported field, skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
if f.CanAddr() {
|
||||
f = f.Addr()
|
||||
}
|
||||
|
||||
elements = append(elements, f.Interface())
|
||||
}
|
||||
|
||||
return elements, nil
|
||||
}
|
||||
|
||||
func string9p(v interface{}) string {
|
||||
if v == nil {
|
||||
return "nil"
|
||||
}
|
||||
|
||||
rv := reflect.Indirect(reflect.ValueOf(v))
|
||||
|
||||
if rv.Kind() != reflect.Struct {
|
||||
panic("not a struct")
|
||||
}
|
||||
|
||||
var s string
|
||||
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
f := rv.Field(i)
|
||||
|
||||
s += fmt.Sprintf(" %v=%v", strings.ToLower(rv.Type().Field(i).Name), f.Interface())
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
58
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/errors.go
generated
vendored
58
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/errors.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// MessageRerror provides both a Go error type and message type.
|
||||
type MessageRerror struct {
|
||||
Ename string
|
||||
}
|
||||
|
||||
// 9p wire errors returned by Session interface methods
|
||||
var (
|
||||
ErrBadattach = new9pError("unknown specifier in attach")
|
||||
ErrBadoffset = new9pError("bad offset")
|
||||
ErrBadcount = new9pError("bad count")
|
||||
ErrBotch = new9pError("9P protocol botch")
|
||||
ErrCreatenondir = new9pError("create in non-directory")
|
||||
ErrDupfid = new9pError("duplicate fid")
|
||||
ErrDuptag = new9pError("duplicate tag")
|
||||
ErrIsdir = new9pError("is a directory")
|
||||
ErrNocreate = new9pError("create prohibited")
|
||||
ErrNomem = new9pError("out of memory")
|
||||
ErrNoremove = new9pError("remove prohibited")
|
||||
ErrNostat = new9pError("stat prohibited")
|
||||
ErrNotfound = new9pError("file not found")
|
||||
ErrNowrite = new9pError("write prohibited")
|
||||
ErrNowstat = new9pError("wstat prohibited")
|
||||
ErrPerm = new9pError("permission denied")
|
||||
ErrUnknownfid = new9pError("unknown fid")
|
||||
ErrBaddir = new9pError("bad directory in wstat")
|
||||
ErrWalknodir = new9pError("walk in non-directory")
|
||||
|
||||
// extra errors not part of the normal protocol
|
||||
|
||||
ErrTimeout = new9pError("fcall timeout") // returned when timing out on the fcall
|
||||
ErrUnknownTag = new9pError("unknown tag")
|
||||
ErrUnknownMsg = new9pError("unknown message") // returned when encountering unknown message type
|
||||
ErrUnexpectedMsg = new9pError("unexpected message") // returned when an unexpected message is encountered
|
||||
ErrWalkLimit = new9pError("too many wnames in walk")
|
||||
ErrClosed = errors.New("closed")
|
||||
)
|
||||
|
||||
// new9pError returns a new 9p error ready for the wire.
|
||||
func new9pError(s string) error {
|
||||
return MessageRerror{Ename: s}
|
||||
}
|
||||
|
||||
// Type ensures that 9p errors can be transparently used as a 9p message in an
|
||||
// Fcall.
|
||||
func (MessageRerror) Type() FcallType {
|
||||
return Rerror
|
||||
}
|
||||
|
||||
func (e MessageRerror) Error() string {
|
||||
return fmt.Sprintf("9p: %v", e.Ename)
|
||||
}
|
||||
142
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/fcall.go
generated
vendored
142
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/fcall.go
generated
vendored
@@ -1,142 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import "fmt"
|
||||
|
||||
// FcallType encodes the message type for the target Fcall.
|
||||
type FcallType uint8
|
||||
|
||||
// Definitions for Fcall's used in 9P2000.
|
||||
const (
|
||||
Tversion FcallType = iota + 100
|
||||
Rversion
|
||||
Tauth
|
||||
Rauth
|
||||
Tattach
|
||||
Rattach
|
||||
Terror
|
||||
Rerror
|
||||
Tflush
|
||||
Rflush
|
||||
Twalk
|
||||
Rwalk
|
||||
Topen
|
||||
Ropen
|
||||
Tcreate
|
||||
Rcreate
|
||||
Tread
|
||||
Rread
|
||||
Twrite
|
||||
Rwrite
|
||||
Tclunk
|
||||
Rclunk
|
||||
Tremove
|
||||
Rremove
|
||||
Tstat
|
||||
Rstat
|
||||
Twstat
|
||||
Rwstat
|
||||
Tmax
|
||||
)
|
||||
|
||||
func (fct FcallType) String() string {
|
||||
switch fct {
|
||||
case Tversion:
|
||||
return "Tversion"
|
||||
case Rversion:
|
||||
return "Rversion"
|
||||
case Tauth:
|
||||
return "Tauth"
|
||||
case Rauth:
|
||||
return "Rauth"
|
||||
case Tattach:
|
||||
return "Tattach"
|
||||
case Rattach:
|
||||
return "Rattach"
|
||||
case Terror:
|
||||
// invalid.
|
||||
return "Terror"
|
||||
case Rerror:
|
||||
return "Rerror"
|
||||
case Tflush:
|
||||
return "Tflush"
|
||||
case Rflush:
|
||||
return "Rflush"
|
||||
case Twalk:
|
||||
return "Twalk"
|
||||
case Rwalk:
|
||||
return "Rwalk"
|
||||
case Topen:
|
||||
return "Topen"
|
||||
case Ropen:
|
||||
return "Ropen"
|
||||
case Tcreate:
|
||||
return "Tcreate"
|
||||
case Rcreate:
|
||||
return "Rcreate"
|
||||
case Tread:
|
||||
return "Tread"
|
||||
case Rread:
|
||||
return "Rread"
|
||||
case Twrite:
|
||||
return "Twrite"
|
||||
case Rwrite:
|
||||
return "Rwrite"
|
||||
case Tclunk:
|
||||
return "Tclunk"
|
||||
case Rclunk:
|
||||
return "Rclunk"
|
||||
case Tremove:
|
||||
return "Tremove"
|
||||
case Rremove:
|
||||
return "Rremove"
|
||||
case Tstat:
|
||||
return "Tstat"
|
||||
case Rstat:
|
||||
return "Rstat"
|
||||
case Twstat:
|
||||
return "Twstat"
|
||||
case Rwstat:
|
||||
return "Rwstat"
|
||||
default:
|
||||
return "Tunknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Fcall defines the fields for sending a 9p formatted message. The type will
|
||||
// be introspected from the Message implementation.
|
||||
type Fcall struct {
|
||||
Type FcallType
|
||||
Tag Tag
|
||||
Message Message
|
||||
}
|
||||
|
||||
func newFcall(tag Tag, msg Message) *Fcall {
|
||||
return &Fcall{
|
||||
Type: msg.Type(),
|
||||
Tag: tag,
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func newErrorFcall(tag Tag, err error) *Fcall {
|
||||
var msg Message
|
||||
|
||||
switch v := err.(type) {
|
||||
case MessageRerror:
|
||||
msg = v
|
||||
case *MessageRerror:
|
||||
msg = *v
|
||||
default:
|
||||
msg = MessageRerror{Ename: v.Error()}
|
||||
}
|
||||
|
||||
return &Fcall{
|
||||
Type: Rerror,
|
||||
Tag: tag,
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func (fc *Fcall) String() string {
|
||||
return fmt.Sprintf("%v(%v) %v", fc.Type, fc.Tag, string9p(fc.Message))
|
||||
}
|
||||
216
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/messages.go
generated
vendored
216
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/messages.go
generated
vendored
@@ -1,216 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Message represents the target of an fcall.
|
||||
type Message interface {
|
||||
// Type returns the type of call for the target message.
|
||||
Type() FcallType
|
||||
}
|
||||
|
||||
// newMessage returns a new instance of the message based on the Fcall type.
|
||||
func newMessage(typ FcallType) (Message, error) {
|
||||
switch typ {
|
||||
case Tversion:
|
||||
return MessageTversion{}, nil
|
||||
case Rversion:
|
||||
return MessageRversion{}, nil
|
||||
case Tauth:
|
||||
return MessageTauth{}, nil
|
||||
case Rauth:
|
||||
return MessageRauth{}, nil
|
||||
case Tattach:
|
||||
return MessageTattach{}, nil
|
||||
case Rattach:
|
||||
return MessageRattach{}, nil
|
||||
case Rerror:
|
||||
return MessageRerror{}, nil
|
||||
case Tflush:
|
||||
return MessageTflush{}, nil
|
||||
case Rflush:
|
||||
return MessageRflush{}, nil // No message body for this response.
|
||||
case Twalk:
|
||||
return MessageTwalk{}, nil
|
||||
case Rwalk:
|
||||
return MessageRwalk{}, nil
|
||||
case Topen:
|
||||
return MessageTopen{}, nil
|
||||
case Ropen:
|
||||
return MessageRopen{}, nil
|
||||
case Tcreate:
|
||||
return MessageTcreate{}, nil
|
||||
case Rcreate:
|
||||
return MessageRcreate{}, nil
|
||||
case Tread:
|
||||
return MessageTread{}, nil
|
||||
case Rread:
|
||||
return MessageRread{}, nil
|
||||
case Twrite:
|
||||
return MessageTwrite{}, nil
|
||||
case Rwrite:
|
||||
return MessageRwrite{}, nil
|
||||
case Tclunk:
|
||||
return MessageTclunk{}, nil
|
||||
case Rclunk:
|
||||
return MessageRclunk{}, nil // no response body
|
||||
case Tremove:
|
||||
return MessageTremove{}, nil
|
||||
case Rremove:
|
||||
return MessageRremove{}, nil
|
||||
case Tstat:
|
||||
return MessageTstat{}, nil
|
||||
case Rstat:
|
||||
return MessageRstat{}, nil
|
||||
case Twstat:
|
||||
return MessageTwstat{}, nil
|
||||
case Rwstat:
|
||||
return MessageRwstat{}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown message type")
|
||||
}
|
||||
|
||||
// MessageVersion encodes the message body for Tversion and Rversion RPC
|
||||
// calls. The body is identical in both directions.
|
||||
type MessageTversion struct {
|
||||
MSize uint32
|
||||
Version string
|
||||
}
|
||||
|
||||
type MessageRversion struct {
|
||||
MSize uint32
|
||||
Version string
|
||||
}
|
||||
|
||||
type MessageTauth struct {
|
||||
Afid Fid
|
||||
Uname string
|
||||
Aname string
|
||||
}
|
||||
|
||||
type MessageRauth struct {
|
||||
Qid Qid
|
||||
}
|
||||
|
||||
type MessageTflush struct {
|
||||
Oldtag Tag
|
||||
}
|
||||
|
||||
type MessageRflush struct{}
|
||||
|
||||
type MessageTattach struct {
|
||||
Fid Fid
|
||||
Afid Fid
|
||||
Uname string
|
||||
Aname string
|
||||
}
|
||||
|
||||
type MessageRattach struct {
|
||||
Qid Qid
|
||||
}
|
||||
|
||||
type MessageTwalk struct {
|
||||
Fid Fid
|
||||
Newfid Fid
|
||||
Wnames []string
|
||||
}
|
||||
|
||||
type MessageRwalk struct {
|
||||
Qids []Qid
|
||||
}
|
||||
|
||||
type MessageTopen struct {
|
||||
Fid Fid
|
||||
Mode Flag
|
||||
}
|
||||
|
||||
type MessageRopen struct {
|
||||
Qid Qid
|
||||
IOUnit uint32
|
||||
}
|
||||
|
||||
type MessageTcreate struct {
|
||||
Fid Fid
|
||||
Name string
|
||||
Perm uint32
|
||||
Mode Flag
|
||||
}
|
||||
|
||||
type MessageRcreate struct {
|
||||
Qid Qid
|
||||
IOUnit uint32
|
||||
}
|
||||
|
||||
type MessageTread struct {
|
||||
Fid Fid
|
||||
Offset uint64
|
||||
Count uint32
|
||||
}
|
||||
|
||||
type MessageRread struct {
|
||||
Data []byte
|
||||
}
|
||||
|
||||
type MessageTwrite struct {
|
||||
Fid Fid
|
||||
Offset uint64
|
||||
Data []byte
|
||||
}
|
||||
|
||||
type MessageRwrite struct {
|
||||
Count uint32
|
||||
}
|
||||
|
||||
type MessageTclunk struct {
|
||||
Fid Fid
|
||||
}
|
||||
|
||||
type MessageRclunk struct{}
|
||||
|
||||
type MessageTremove struct {
|
||||
Fid Fid
|
||||
}
|
||||
|
||||
type MessageRremove struct{}
|
||||
|
||||
type MessageTstat struct {
|
||||
Fid Fid
|
||||
}
|
||||
|
||||
type MessageRstat struct {
|
||||
Stat Dir
|
||||
}
|
||||
|
||||
type MessageTwstat struct {
|
||||
Fid Fid
|
||||
Stat Dir
|
||||
}
|
||||
|
||||
type MessageRwstat struct{}
|
||||
|
||||
func (MessageTversion) Type() FcallType { return Tversion }
|
||||
func (MessageRversion) Type() FcallType { return Rversion }
|
||||
func (MessageTauth) Type() FcallType { return Tauth }
|
||||
func (MessageRauth) Type() FcallType { return Rauth }
|
||||
func (MessageTflush) Type() FcallType { return Tflush }
|
||||
func (MessageRflush) Type() FcallType { return Rflush }
|
||||
func (MessageTattach) Type() FcallType { return Tattach }
|
||||
func (MessageRattach) Type() FcallType { return Rattach }
|
||||
func (MessageTwalk) Type() FcallType { return Twalk }
|
||||
func (MessageRwalk) Type() FcallType { return Rwalk }
|
||||
func (MessageTopen) Type() FcallType { return Topen }
|
||||
func (MessageRopen) Type() FcallType { return Ropen }
|
||||
func (MessageTcreate) Type() FcallType { return Tcreate }
|
||||
func (MessageRcreate) Type() FcallType { return Rcreate }
|
||||
func (MessageTread) Type() FcallType { return Tread }
|
||||
func (MessageRread) Type() FcallType { return Rread }
|
||||
func (MessageTwrite) Type() FcallType { return Twrite }
|
||||
func (MessageRwrite) Type() FcallType { return Rwrite }
|
||||
func (MessageTclunk) Type() FcallType { return Tclunk }
|
||||
func (MessageRclunk) Type() FcallType { return Rclunk }
|
||||
func (MessageTremove) Type() FcallType { return Tremove }
|
||||
func (MessageRremove) Type() FcallType { return Rremove }
|
||||
func (MessageTstat) Type() FcallType { return Tstat }
|
||||
func (MessageRstat) Type() FcallType { return Rstat }
|
||||
func (MessageTwstat) Type() FcallType { return Twstat }
|
||||
func (MessageRwstat) Type() FcallType { return Rwstat }
|
||||
49
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/overflow.go
generated
vendored
49
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/overflow.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Overflow will return a positive number, indicating there was an overflow for
|
||||
// the error.
|
||||
func Overflow(err error) int {
|
||||
if of, ok := err.(overflow); ok {
|
||||
return of.Size()
|
||||
}
|
||||
|
||||
// traverse cause, if above fails.
|
||||
if causal, ok := err.(interface {
|
||||
Cause() error
|
||||
}); ok {
|
||||
return Overflow(causal.Cause())
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// overflow is a resolvable error type that can help callers negotiate
|
||||
// session msize. If this error is encountered, no message was sent.
|
||||
//
|
||||
// The return value of `Size()` represents the number of bytes that would have
|
||||
// been truncated if the message were sent. This IS NOT the optimal buffer size
|
||||
// for operations like read and write.
|
||||
//
|
||||
// In the case of `Twrite`, the caller can Size() from the local size to get an
|
||||
// optimally size buffer or the write can simply be truncated to `len(buf) -
|
||||
// err.Size()`.
|
||||
//
|
||||
// For the most part, no users of this package should see this error in
|
||||
// practice. If this escapes the Session interface, it is a bug.
|
||||
type overflow interface {
|
||||
Size() int // number of bytes overflowed.
|
||||
}
|
||||
|
||||
type overflowErr struct {
|
||||
size int // number of bytes overflowed
|
||||
}
|
||||
|
||||
func (o overflowErr) Error() string {
|
||||
return fmt.Sprintf("message overflowed %d bytes", o.size)
|
||||
}
|
||||
|
||||
func (o overflowErr) Size() int {
|
||||
return o.size
|
||||
}
|
||||
93
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/readdir.go
generated
vendored
93
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/readdir.go
generated
vendored
@@ -1,93 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"context"
|
||||
)
|
||||
|
||||
// ReaddirAll reads all the directory entries for the resource fid.
|
||||
func ReaddirAll(session Session, fid Fid) ([]Dir, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Readdir helps one to implement the server-side of Session.Read on
|
||||
// directories.
|
||||
type Readdir struct {
|
||||
nextfn func() (Dir, error)
|
||||
buf *Dir // one-item buffer
|
||||
codec Codec
|
||||
offset int64
|
||||
}
|
||||
|
||||
// NewReaddir returns a new Readdir to assist implementing server-side Readdir.
|
||||
// The codec will be used to decode messages with Dir entries. The provided
|
||||
// function next will be called until io.EOF is returned.
|
||||
func NewReaddir(codec Codec, next func() (Dir, error)) *Readdir {
|
||||
return &Readdir{
|
||||
nextfn: next,
|
||||
codec: codec,
|
||||
}
|
||||
}
|
||||
|
||||
// NewFixedReaddir returns a Readdir that will returned a fixed set of
|
||||
// directory entries.
|
||||
func NewFixedReaddir(codec Codec, dir []Dir) *Readdir {
|
||||
dirs := make([]Dir, len(dir))
|
||||
copy(dirs, dir) // make our own copy!
|
||||
|
||||
return NewReaddir(codec,
|
||||
func() (Dir, error) {
|
||||
if len(dirs) == 0 {
|
||||
return Dir{}, io.EOF
|
||||
}
|
||||
|
||||
d := dirs[0]
|
||||
dirs = dirs[1:]
|
||||
return d, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (rd *Readdir) Read(ctx context.Context, p []byte, offset int64) (n int, err error) {
|
||||
if rd.offset != offset {
|
||||
return 0, ErrBadoffset
|
||||
}
|
||||
|
||||
p = p[:0:len(p)]
|
||||
for len(p) < cap(p) {
|
||||
var d Dir
|
||||
if rd.buf != nil {
|
||||
d = *rd.buf
|
||||
rd.buf = nil
|
||||
} else {
|
||||
d, err = rd.nextfn()
|
||||
if err != nil {
|
||||
goto done
|
||||
}
|
||||
}
|
||||
|
||||
var dp []byte
|
||||
dp, err = rd.codec.Marshal(d)
|
||||
if err != nil {
|
||||
goto done
|
||||
}
|
||||
|
||||
if len(p)+len(dp) > cap(p) {
|
||||
// will over fill buffer. save item and exit.
|
||||
rd.buf = &d
|
||||
goto done
|
||||
}
|
||||
|
||||
p = append(p, dp...)
|
||||
}
|
||||
|
||||
done:
|
||||
if err == io.EOF && len(p) > 0 {
|
||||
// Don't let io.EOF escape if we've written to p. 9p doesn't handle
|
||||
// this like Go.
|
||||
err = nil
|
||||
}
|
||||
|
||||
rd.offset += int64(len(p))
|
||||
return len(p), err
|
||||
}
|
||||
257
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/server.go
generated
vendored
257
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/server.go
generated
vendored
@@ -1,257 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
)
|
||||
|
||||
// TODO(stevvooe): Add net/http.Server-like type here to manage connections.
|
||||
// Coupled with Handler mux, we can get a very http-like experience for 9p
|
||||
// servers.
|
||||
|
||||
// ServeConn the 9p handler over the provided network connection.
|
||||
func ServeConn(ctx context.Context, cn net.Conn, handler Handler) error {
|
||||
|
||||
// TODO(stevvooe): It would be nice if the handler could declare the
|
||||
// supported version. Before we had handler, we used the session to get
|
||||
// the version (msize, version := session.Version()). We must decided if
|
||||
// we want to proxy version and message size decisions all the back to the
|
||||
// origin server or make those decisions at each link of a proxy chain.
|
||||
|
||||
ch := newChannel(cn, codec9p{}, DefaultMSize)
|
||||
negctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// TODO(stevvooe): For now, we negotiate here. It probably makes sense to
|
||||
// do this outside of this function and then pass in a ready made channel.
|
||||
// We are not really ready to export the channel type yet.
|
||||
|
||||
if err := servernegotiate(negctx, ch, DefaultVersion); err != nil {
|
||||
// TODO(stevvooe): Need better error handling and retry support here.
|
||||
return fmt.Errorf("error negotiating version: %s", err)
|
||||
}
|
||||
|
||||
ctx = withVersion(ctx, DefaultVersion)
|
||||
|
||||
c := &conn{
|
||||
ctx: ctx,
|
||||
ch: ch,
|
||||
handler: handler,
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
|
||||
return c.serve()
|
||||
}
|
||||
|
||||
// conn plays role of session dispatch for handler in a server.
|
||||
type conn struct {
|
||||
ctx context.Context
|
||||
session Session
|
||||
ch Channel
|
||||
handler Handler
|
||||
|
||||
once sync.Once
|
||||
closed chan struct{}
|
||||
err error // terminal error for the conn
|
||||
}
|
||||
|
||||
// activeRequest includes information about the active request.
|
||||
type activeRequest struct {
|
||||
ctx context.Context
|
||||
request *Fcall
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
// serve messages on the connection until an error is encountered.
|
||||
func (c *conn) serve() error {
|
||||
tags := map[Tag]*activeRequest{} // active requests
|
||||
|
||||
requests := make(chan *Fcall) // sync, read-limited
|
||||
responses := make(chan *Fcall) // sync, goroutine consumed
|
||||
completed := make(chan *Fcall) // sync, send in goroutine per request
|
||||
|
||||
// read loop
|
||||
go c.read(requests)
|
||||
go c.write(responses)
|
||||
|
||||
log.Println("server.run()")
|
||||
for {
|
||||
select {
|
||||
case req := <-requests:
|
||||
if _, ok := tags[req.Tag]; ok {
|
||||
select {
|
||||
case responses <- newErrorFcall(req.Tag, ErrDuptag):
|
||||
// Send to responses, bypass tag management.
|
||||
case <-c.ctx.Done():
|
||||
return c.ctx.Err()
|
||||
case <-c.closed:
|
||||
return c.err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch msg := req.Message.(type) {
|
||||
case MessageTflush:
|
||||
log.Println("server: flushing message", msg.Oldtag)
|
||||
|
||||
var resp *Fcall
|
||||
// check if we have actually know about the requested flush
|
||||
active, ok := tags[msg.Oldtag]
|
||||
if ok {
|
||||
active.cancel() // propagate cancellation to callees
|
||||
delete(tags, msg.Oldtag)
|
||||
resp = newFcall(req.Tag, MessageRflush{})
|
||||
} else {
|
||||
resp = newErrorFcall(req.Tag, ErrUnknownTag)
|
||||
}
|
||||
|
||||
select {
|
||||
case responses <- resp:
|
||||
// bypass tag management in completed.
|
||||
case <-c.ctx.Done():
|
||||
return c.ctx.Err()
|
||||
case <-c.closed:
|
||||
return c.err
|
||||
}
|
||||
default:
|
||||
// Allows us to session handlers to cancel processing of the fcall
|
||||
// through context.
|
||||
ctx, cancel := context.WithCancel(c.ctx)
|
||||
|
||||
// The contents of these instances are only writable in the main
|
||||
// server loop. The value of tag will not change.
|
||||
tags[req.Tag] = &activeRequest{
|
||||
ctx: ctx,
|
||||
request: req,
|
||||
cancel: cancel,
|
||||
}
|
||||
|
||||
go func(ctx context.Context, req *Fcall) {
|
||||
// TODO(stevvooe): Re-write incoming Treads so that handler
|
||||
// can always respond with a message of the correct msize.
|
||||
|
||||
var resp *Fcall
|
||||
msg, err := c.handler.Handle(ctx, req.Message)
|
||||
if err != nil {
|
||||
// all handler errors are forwarded as protocol errors.
|
||||
resp = newErrorFcall(req.Tag, err)
|
||||
} else {
|
||||
resp = newFcall(req.Tag, msg)
|
||||
}
|
||||
|
||||
select {
|
||||
case completed <- resp:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-c.closed:
|
||||
return
|
||||
}
|
||||
}(ctx, req)
|
||||
}
|
||||
case resp := <-completed:
|
||||
// only responses that flip the tag state traverse this section.
|
||||
active, ok := tags[resp.Tag]
|
||||
if !ok {
|
||||
// The tag is no longer active. Likely a flushed message.
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case responses <- resp:
|
||||
case <-active.ctx.Done():
|
||||
// the context was canceled for some reason, perhaps timeout or
|
||||
// due to a flush call. We treat this as a condition where a
|
||||
// response should not be sent.
|
||||
log.Println("canceled", resp, active.ctx.Err())
|
||||
}
|
||||
delete(tags, resp.Tag)
|
||||
case <-c.ctx.Done():
|
||||
return c.ctx.Err()
|
||||
case <-c.closed:
|
||||
return c.err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read takes requests off the channel and sends them on requests.
|
||||
func (c *conn) read(requests chan *Fcall) {
|
||||
for {
|
||||
req := new(Fcall)
|
||||
if err := c.ch.ReadFcall(c.ctx, req); err != nil {
|
||||
if err, ok := err.(net.Error); ok {
|
||||
if err.Timeout() || err.Temporary() {
|
||||
// TODO(stevvooe): A full idle timeout on the connection
|
||||
// should be enforced here. No logging because it is quite
|
||||
// chatty.
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
c.CloseWithError(fmt.Errorf("error reading fcall: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case requests <- req:
|
||||
case <-c.ctx.Done():
|
||||
c.CloseWithError(c.ctx.Err())
|
||||
return
|
||||
case <-c.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) write(responses chan *Fcall) {
|
||||
for {
|
||||
select {
|
||||
case resp := <-responses:
|
||||
// TODO(stevvooe): Correctly protect againt overflowing msize from
|
||||
// handler. This can be done above, in the main message handler
|
||||
// loop, by adjusting incoming Tread calls to have a Count that
|
||||
// won't overflow the msize.
|
||||
|
||||
if err := c.ch.WriteFcall(c.ctx, resp); err != nil {
|
||||
if err, ok := err.(net.Error); ok {
|
||||
if err.Timeout() || err.Temporary() {
|
||||
// TODO(stevvooe): A full idle timeout on the
|
||||
// connection should be enforced here. We log here,
|
||||
// since this is less common.
|
||||
log.Printf("9p server: temporary error writing fcall: %v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
c.CloseWithError(fmt.Errorf("error writing fcall: %v", err))
|
||||
return
|
||||
}
|
||||
case <-c.ctx.Done():
|
||||
c.CloseWithError(c.ctx.Err())
|
||||
return
|
||||
case <-c.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) Close() error {
|
||||
return c.CloseWithError(nil)
|
||||
}
|
||||
|
||||
func (c *conn) CloseWithError(err error) error {
|
||||
c.once.Do(func() {
|
||||
if err == nil {
|
||||
err = ErrClosed
|
||||
}
|
||||
|
||||
c.err = err
|
||||
close(c.closed)
|
||||
})
|
||||
|
||||
return c.err
|
||||
}
|
||||
42
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/session.go
generated
vendored
42
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/session.go
generated
vendored
@@ -1,42 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import "context"
|
||||
|
||||
// Session provides the central abstraction for a 9p connection. Clients
|
||||
// implement sessions and servers serve sessions. Sessions can be proxied by
|
||||
// serving up a client session.
|
||||
//
|
||||
// The interface is also wired up with full context support to manage timeouts
|
||||
// and resource clean up.
|
||||
//
|
||||
// Session represents the operations covered in section 5 of the plan 9 manual
|
||||
// (http://man.cat-v.org/plan_9/5/). Requests are managed internally, so the
|
||||
// Flush method is handled by the internal implementation. Consider preceeding
|
||||
// these all with context to control request timeout.
|
||||
type Session interface {
|
||||
Auth(ctx context.Context, afid Fid, uname, aname string) (Qid, error)
|
||||
Attach(ctx context.Context, fid, afid Fid, uname, aname string) (Qid, error)
|
||||
Clunk(ctx context.Context, fid Fid) error
|
||||
Remove(ctx context.Context, fid Fid) error
|
||||
Walk(ctx context.Context, fid Fid, newfid Fid, names ...string) ([]Qid, error)
|
||||
|
||||
// Read follows the semantics of io.ReaderAt.ReadAtt method except it takes
|
||||
// a contxt and Fid.
|
||||
Read(ctx context.Context, fid Fid, p []byte, offset int64) (n int, err error)
|
||||
|
||||
// Write follows the semantics of io.WriterAt.WriteAt except takes a context and an Fid.
|
||||
//
|
||||
// If n == len(p), no error is returned.
|
||||
// If n < len(p), io.ErrShortWrite will be returned.
|
||||
Write(ctx context.Context, fid Fid, p []byte, offset int64) (n int, err error)
|
||||
|
||||
Open(ctx context.Context, fid Fid, mode Flag) (Qid, uint32, error)
|
||||
Create(ctx context.Context, parent Fid, name string, perm uint32, mode Flag) (Qid, uint32, error)
|
||||
Stat(ctx context.Context, fid Fid) (Dir, error)
|
||||
WStat(ctx context.Context, fid Fid, dir Dir) error
|
||||
|
||||
// Version returns the supported version and msize of the session. This
|
||||
// can be affected by negotiating or the level of support provided by the
|
||||
// session implementation.
|
||||
Version() (msize int, version string)
|
||||
}
|
||||
250
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/transport.go
generated
vendored
250
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/transport.go
generated
vendored
@@ -1,250 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"context"
|
||||
)
|
||||
|
||||
// roundTripper manages the request and response from the client-side. A
|
||||
// roundTripper must abide by similar rules to the http.RoundTripper.
|
||||
// Typically, the roundTripper will manage tag assignment and message
|
||||
// serialization.
|
||||
type roundTripper interface {
|
||||
send(ctx context.Context, msg Message) (Message, error)
|
||||
}
|
||||
|
||||
// transport plays the role of being a client channel manager. It multiplexes
|
||||
// function calls onto the wire and dispatches responses to blocking calls to
|
||||
// send. On the whole, transport is thread-safe for calling send
|
||||
type transport struct {
|
||||
ctx context.Context
|
||||
ch Channel
|
||||
requests chan *fcallRequest
|
||||
|
||||
shutdown chan struct{}
|
||||
once sync.Once // protect closure of shutdown
|
||||
closed chan struct{}
|
||||
|
||||
tags uint16
|
||||
}
|
||||
|
||||
var _ roundTripper = &transport{}
|
||||
|
||||
func newTransport(ctx context.Context, ch Channel) roundTripper {
|
||||
t := &transport{
|
||||
ctx: ctx,
|
||||
ch: ch,
|
||||
requests: make(chan *fcallRequest),
|
||||
shutdown: make(chan struct{}),
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
|
||||
go t.handle()
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// fcallRequest encompasses the request to send a message via fcall.
|
||||
type fcallRequest struct {
|
||||
ctx context.Context
|
||||
message Message
|
||||
response chan *Fcall
|
||||
err chan error
|
||||
}
|
||||
|
||||
func newFcallRequest(ctx context.Context, msg Message) *fcallRequest {
|
||||
return &fcallRequest{
|
||||
ctx: ctx,
|
||||
message: msg,
|
||||
response: make(chan *Fcall, 1),
|
||||
err: make(chan error, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *transport) send(ctx context.Context, msg Message) (Message, error) {
|
||||
req := newFcallRequest(ctx, msg)
|
||||
|
||||
// dispatch the request.
|
||||
select {
|
||||
case <-t.closed:
|
||||
return nil, ErrClosed
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case t.requests <- req:
|
||||
}
|
||||
|
||||
// wait for the response.
|
||||
select {
|
||||
case <-t.closed:
|
||||
return nil, ErrClosed
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case err := <-req.err:
|
||||
return nil, err
|
||||
case resp := <-req.response:
|
||||
if resp.Type == Rerror {
|
||||
// pack the error into something useful
|
||||
respmesg, ok := resp.Message.(MessageRerror)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid error response: %v", resp)
|
||||
}
|
||||
|
||||
return nil, respmesg
|
||||
}
|
||||
|
||||
return resp.Message, nil
|
||||
}
|
||||
}
|
||||
|
||||
// allocateTag returns a valid tag given a tag pool map. It receives a hint as
|
||||
// to where to start the tag search. It returns an error if the allocation is
|
||||
// not possible. The provided map must not contain NOTAG as a key.
|
||||
func allocateTag(r *fcallRequest, m map[Tag]*fcallRequest, hint Tag) (Tag, error) {
|
||||
// The tag pool is depleted if 65535 (0xFFFF) tags are taken.
|
||||
if len(m) >= 0xFFFF {
|
||||
return 0, errors.New("tag pool depleted")
|
||||
}
|
||||
|
||||
// Look for the first tag that doesn't exist in the map and return it.
|
||||
for i := 0; i < 0xFFFF; i++ {
|
||||
hint++
|
||||
if hint == NOTAG {
|
||||
hint = 0
|
||||
}
|
||||
|
||||
if _, exists := m[hint]; !exists {
|
||||
return hint, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("allocateTag: unexpected error")
|
||||
}
|
||||
|
||||
// handle takes messages off the wire and wakes up the waiting tag call.
|
||||
func (t *transport) handle() {
|
||||
defer func() {
|
||||
log.Println("exited handle loop")
|
||||
close(t.closed)
|
||||
}()
|
||||
|
||||
// the following variable block are protected components owned by this thread.
|
||||
var (
|
||||
responses = make(chan *Fcall)
|
||||
// outstanding provides a map of tags to outstanding requests.
|
||||
outstanding = map[Tag]*fcallRequest{}
|
||||
selected Tag
|
||||
)
|
||||
|
||||
// loop to read messages off of the connection
|
||||
go func() {
|
||||
defer func() {
|
||||
log.Println("exited read loop")
|
||||
t.close() // single main loop
|
||||
}()
|
||||
loop:
|
||||
for {
|
||||
fcall := new(Fcall)
|
||||
if err := t.ch.ReadFcall(t.ctx, fcall); err != nil {
|
||||
switch err := err.(type) {
|
||||
case net.Error:
|
||||
if err.Timeout() || err.Temporary() {
|
||||
// BUG(stevvooe): There may be partial reads under
|
||||
// timeout errors where this is actually fatal.
|
||||
|
||||
// can only retry if we haven't offset the frame.
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("fatal error reading msg:", err)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-t.ctx.Done():
|
||||
return
|
||||
case <-t.closed:
|
||||
log.Println("transport closed")
|
||||
return
|
||||
case responses <- fcall:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case req := <-t.requests:
|
||||
var err error
|
||||
|
||||
selected, err = allocateTag(req, outstanding, selected)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
continue
|
||||
}
|
||||
|
||||
outstanding[selected] = req
|
||||
fcall := newFcall(selected, req.message)
|
||||
|
||||
// TODO(stevvooe): Consider the case of requests that never
|
||||
// receive a response. We need to remove the fcall context from
|
||||
// the tag map and dealloc the tag. We may also want to send a
|
||||
// flush for the tag.
|
||||
if err := t.ch.WriteFcall(req.ctx, fcall); err != nil {
|
||||
delete(outstanding, fcall.Tag)
|
||||
req.err <- err
|
||||
}
|
||||
case b := <-responses:
|
||||
req, ok := outstanding[b.Tag]
|
||||
if !ok {
|
||||
// BUG(stevvooe): The exact handling of an unknown tag is
|
||||
// unclear at this point. These may not necessarily fatal to
|
||||
// the session, since they could be messages that the client no
|
||||
// longer cares for. When we figure this out, replace this
|
||||
// panic with something more sensible.
|
||||
panic(fmt.Sprintf("unknown tag received: %v", b))
|
||||
}
|
||||
|
||||
// BUG(stevvooe): Must detect duplicate tag and ensure that we are
|
||||
// waking up the right caller. If a duplicate is received, the
|
||||
// entry should not be deleted.
|
||||
delete(outstanding, b.Tag)
|
||||
|
||||
req.response <- b
|
||||
|
||||
// TODO(stevvooe): Reclaim tag id.
|
||||
case <-t.shutdown:
|
||||
return
|
||||
case <-t.ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *transport) flush(ctx context.Context, tag Tag) error {
|
||||
// TODO(stevvooe): We need to fire and forget flush messages when a call
|
||||
// context gets cancelled.
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (t *transport) Close() error {
|
||||
t.close()
|
||||
|
||||
select {
|
||||
case <-t.closed:
|
||||
return nil
|
||||
case <-t.ctx.Done():
|
||||
return t.ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// close starts the shutdown process.
|
||||
func (t *transport) close() {
|
||||
t.once.Do(func() {
|
||||
close(t.shutdown)
|
||||
})
|
||||
}
|
||||
149
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/types.go
generated
vendored
149
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/types.go
generated
vendored
@@ -1,149 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultMSize messages size used to establish a session.
|
||||
DefaultMSize = 64 << 10
|
||||
|
||||
// DefaultVersion for this package. Currently, the only supported version.
|
||||
DefaultVersion = "9P2000"
|
||||
)
|
||||
|
||||
// Mode constants for use Dir.Mode.
|
||||
const (
|
||||
DMDIR = 0x80000000 // mode bit for directories
|
||||
DMAPPEND = 0x40000000 // mode bit for append only files
|
||||
DMEXCL = 0x20000000 // mode bit for exclusive use files
|
||||
DMMOUNT = 0x10000000 // mode bit for mounted channel
|
||||
DMAUTH = 0x08000000 // mode bit for authentication file
|
||||
DMTMP = 0x04000000 // mode bit for non-backed-up files
|
||||
|
||||
// 9p2000.u extensions
|
||||
|
||||
DMSYMLINK = 0x02000000
|
||||
DMDEVICE = 0x00800000
|
||||
DMNAMEDPIPE = 0x00200000
|
||||
DMSOCKET = 0x00100000
|
||||
DMSETUID = 0x00080000
|
||||
DMSETGID = 0x00040000
|
||||
|
||||
DMREAD = 0x4 // mode bit for read permission
|
||||
DMWRITE = 0x2 // mode bit for write permission
|
||||
DMEXEC = 0x1 // mode bit for execute permission
|
||||
)
|
||||
|
||||
// Flag defines the flag type for use with open and create
|
||||
type Flag uint8
|
||||
|
||||
// Constants to use when opening files.
|
||||
const (
|
||||
OREAD Flag = 0x00 // open for read
|
||||
OWRITE Flag = 0x01 // write
|
||||
ORDWR Flag = 0x02 // read and write
|
||||
OEXEC Flag = 0x03 // execute, == read but check execute permission
|
||||
|
||||
// PROPOSAL(stevvooe): Possible protocal extension to allow the create of
|
||||
// symlinks. Initially, the link is created with no value. Read and write
|
||||
// to read and set the link value.
|
||||
|
||||
OSYMLINK Flag = 0x04
|
||||
|
||||
OTRUNC Flag = 0x10 // or'ed in (except for exec), truncate file first
|
||||
OCEXEC Flag = 0x20 // or'ed in, close on exec
|
||||
ORCLOSE Flag = 0x40 // or'ed in, remove on close
|
||||
)
|
||||
|
||||
// QType indicates the type of a resource within the Qid.
|
||||
type QType uint8
|
||||
|
||||
// Constants for use in Qid to indicate resource type.
|
||||
const (
|
||||
QTDIR QType = 0x80 // type bit for directories
|
||||
QTAPPEND QType = 0x40 // type bit for append only files
|
||||
QTEXCL QType = 0x20 // type bit for exclusive use files
|
||||
QTMOUNT QType = 0x10 // type bit for mounted channel
|
||||
QTAUTH QType = 0x08 // type bit for authentication file
|
||||
QTTMP QType = 0x04 // type bit for not-backed-up file
|
||||
QTFILE QType = 0x00 // plain file
|
||||
)
|
||||
|
||||
func (qt QType) String() string {
|
||||
switch qt {
|
||||
case QTDIR:
|
||||
return "dir"
|
||||
case QTAPPEND:
|
||||
return "append"
|
||||
case QTEXCL:
|
||||
return "excl"
|
||||
case QTMOUNT:
|
||||
return "mount"
|
||||
case QTAUTH:
|
||||
return "auth"
|
||||
case QTTMP:
|
||||
return "tmp"
|
||||
case QTFILE:
|
||||
return "file"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// Tag uniquely identifies an outstanding fcall in a 9p session.
|
||||
type Tag uint16
|
||||
|
||||
// NOTAG is a reserved values for messages sent before establishing a session,
|
||||
// such as Tversion.
|
||||
const NOTAG Tag = ^Tag(0)
|
||||
|
||||
// Fid defines a type to hold Fid values.
|
||||
type Fid uint32
|
||||
|
||||
// NOFID indicates the lack of an Fid.
|
||||
const NOFID Fid = ^Fid(0)
|
||||
|
||||
// Qid indicates the type, path and version of the resource returned by a
|
||||
// server. It is only valid for a session.
|
||||
//
|
||||
// Typically, a client maintains a mapping of Fid-Qid as Qids are returned by
|
||||
// the server.
|
||||
type Qid struct {
|
||||
Type QType `9p:"type,1"`
|
||||
Version uint32
|
||||
Path uint64
|
||||
}
|
||||
|
||||
func (qid Qid) String() string {
|
||||
return fmt.Sprintf("qid(%v, v=%x, p=%x)",
|
||||
qid.Type, qid.Version, qid.Path)
|
||||
}
|
||||
|
||||
// Dir defines the structure used for expressing resources in stat/wstat and
|
||||
// when reading directories.
|
||||
type Dir struct {
|
||||
Type uint16
|
||||
Dev uint32
|
||||
Qid Qid
|
||||
Mode uint32
|
||||
|
||||
// BUG(stevvooe): The Year 2038 is coming soon. 9p wire protocol has these
|
||||
// as 4 byte epoch times. Some possibilities include time dilation fields
|
||||
// or atemporal files. We can also just not use them and set them to zero.
|
||||
|
||||
AccessTime time.Time
|
||||
ModTime time.Time
|
||||
|
||||
Length uint64
|
||||
Name string
|
||||
UID string
|
||||
GID string
|
||||
MUID string
|
||||
}
|
||||
|
||||
func (d Dir) String() string {
|
||||
return fmt.Sprintf("dir(%v mode=%v atime=%v mtime=%v length=%v name=%v uid=%v gid=%v muid=%v)",
|
||||
d.Qid, d.Mode, d.AccessTime, d.ModTime, d.Length, d.Name, d.UID, d.GID, d.MUID)
|
||||
}
|
||||
112
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/version.go
generated
vendored
112
src/cmd/linuxkit/vendor/github.com/docker/go-p9p/version.go
generated
vendored
@@ -1,112 +0,0 @@
|
||||
package p9p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"context"
|
||||
)
|
||||
|
||||
// NOTE(stevvooe): This file contains functions for negotiating version on the
|
||||
// client and server. There are some nasty details to get right for
|
||||
// downgrading the connection on the server-side that are not present yet.
|
||||
// Really, these should be refactored into some sort of channel type that can
|
||||
// support resets through version messages during the protocol exchange.
|
||||
|
||||
// clientnegotiate negiotiates the protocol version using channel, blocking
|
||||
// until a response is received. The received value will be the version
|
||||
// implemented by the server.
|
||||
func clientnegotiate(ctx context.Context, ch Channel, version string) (string, error) {
|
||||
req := newFcall(NOTAG, MessageTversion{
|
||||
MSize: uint32(ch.MSize()),
|
||||
Version: version,
|
||||
})
|
||||
|
||||
if err := ch.WriteFcall(ctx, req); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp := new(Fcall)
|
||||
if err := ch.ReadFcall(ctx, resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch v := resp.Message.(type) {
|
||||
case MessageRversion:
|
||||
|
||||
if v.Version != version {
|
||||
// TODO(stevvooe): A stubborn client indeed!
|
||||
return "", fmt.Errorf("unsupported server version: %v", version)
|
||||
}
|
||||
|
||||
if int(v.MSize) < ch.MSize() {
|
||||
// upgrade msize if server differs.
|
||||
ch.SetMSize(int(v.MSize))
|
||||
}
|
||||
|
||||
return v.Version, nil
|
||||
case error:
|
||||
return "", v
|
||||
default:
|
||||
return "", ErrUnexpectedMsg
|
||||
}
|
||||
}
|
||||
|
||||
// servernegotiate blocks until a version message is received or a timeout
|
||||
// occurs. The msize for the tranport will be set from the negotiation. If
|
||||
// negotiate returns nil, a server may proceed with the connection.
|
||||
//
|
||||
// In the future, it might be better to handle the version messages in a
|
||||
// separate object that manages the session. Each set of version requests
|
||||
// effectively "reset" a connection, meaning all fids get clunked and all
|
||||
// outstanding IO is aborted. This is probably slightly racy, in practice with
|
||||
// a misbehaved client. The main issue is that we cannot tell which session
|
||||
// messages belong to.
|
||||
func servernegotiate(ctx context.Context, ch Channel, version string) error {
|
||||
// wait for the version message over the transport.
|
||||
req := new(Fcall)
|
||||
if err := ch.ReadFcall(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mv, ok := req.Message.(MessageTversion)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected version message: %v", mv)
|
||||
}
|
||||
|
||||
respmsg := MessageRversion{
|
||||
Version: version,
|
||||
}
|
||||
|
||||
if mv.Version != version {
|
||||
// TODO(stevvooe): Not the best place to do version handling. We need
|
||||
// to have a way to pass supported versions into this method then have
|
||||
// it return the actual version. For now, respond with 9P2000 for
|
||||
// anything that doesn't match the provided version string.
|
||||
//
|
||||
// version(9) says "The server may respond with the client’s
|
||||
// version string, or a version string identifying an earlier
|
||||
// defined protocol version. Currently, the only defined
|
||||
// version is the 6 characters 9P2000." Therefore, it is always
|
||||
// OK to respond with this.
|
||||
respmsg.Version = "9P2000"
|
||||
}
|
||||
|
||||
if int(mv.MSize) < ch.MSize() {
|
||||
// if the server msize is too large, use the client's suggested msize.
|
||||
ch.SetMSize(int(mv.MSize))
|
||||
respmsg.MSize = mv.MSize
|
||||
} else {
|
||||
respmsg.MSize = uint32(ch.MSize())
|
||||
}
|
||||
|
||||
resp := newFcall(NOTAG, respmsg)
|
||||
if err := ch.WriteFcall(ctx, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if respmsg.Version == "unknown" {
|
||||
return fmt.Errorf("bad version negotiation")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
139
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
139
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
@@ -1,139 +0,0 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package ptypes
|
||||
|
||||
// This file implements functions to marshal proto.Message to/from
|
||||
// google.protobuf.Any message.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes/any"
|
||||
)
|
||||
|
||||
const googleApis = "type.googleapis.com/"
|
||||
|
||||
// AnyMessageName returns the name of the message contained in a google.protobuf.Any message.
|
||||
//
|
||||
// Note that regular type assertions should be done using the Is
|
||||
// function. AnyMessageName is provided for less common use cases like filtering a
|
||||
// sequence of Any messages based on a set of allowed message type names.
|
||||
func AnyMessageName(any *any.Any) (string, error) {
|
||||
if any == nil {
|
||||
return "", fmt.Errorf("message is nil")
|
||||
}
|
||||
slash := strings.LastIndex(any.TypeUrl, "/")
|
||||
if slash < 0 {
|
||||
return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
|
||||
}
|
||||
return any.TypeUrl[slash+1:], nil
|
||||
}
|
||||
|
||||
// MarshalAny takes the protocol buffer and encodes it into google.protobuf.Any.
|
||||
func MarshalAny(pb proto.Message) (*any.Any, error) {
|
||||
value, err := proto.Marshal(pb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &any.Any{TypeUrl: googleApis + proto.MessageName(pb), Value: value}, nil
|
||||
}
|
||||
|
||||
// DynamicAny is a value that can be passed to UnmarshalAny to automatically
|
||||
// allocate a proto.Message for the type specified in a google.protobuf.Any
|
||||
// message. The allocated message is stored in the embedded proto.Message.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var x ptypes.DynamicAny
|
||||
// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
|
||||
// fmt.Printf("unmarshaled message: %v", x.Message)
|
||||
type DynamicAny struct {
|
||||
proto.Message
|
||||
}
|
||||
|
||||
// Empty returns a new proto.Message of the type specified in a
|
||||
// google.protobuf.Any message. It returns an error if corresponding message
|
||||
// type isn't linked in.
|
||||
func Empty(any *any.Any) (proto.Message, error) {
|
||||
aname, err := AnyMessageName(any)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := proto.MessageType(aname)
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("any: message type %q isn't linked in", aname)
|
||||
}
|
||||
return reflect.New(t.Elem()).Interface().(proto.Message), nil
|
||||
}
|
||||
|
||||
// UnmarshalAny parses the protocol buffer representation in a google.protobuf.Any
|
||||
// message and places the decoded result in pb. It returns an error if type of
|
||||
// contents of Any message does not match type of pb message.
|
||||
//
|
||||
// pb can be a proto.Message, or a *DynamicAny.
|
||||
func UnmarshalAny(any *any.Any, pb proto.Message) error {
|
||||
if d, ok := pb.(*DynamicAny); ok {
|
||||
if d.Message == nil {
|
||||
var err error
|
||||
d.Message, err = Empty(any)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return UnmarshalAny(any, d.Message)
|
||||
}
|
||||
|
||||
aname, err := AnyMessageName(any)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mname := proto.MessageName(pb)
|
||||
if aname != mname {
|
||||
return fmt.Errorf("mismatched message type: got %q want %q", aname, mname)
|
||||
}
|
||||
return proto.Unmarshal(any.Value, pb)
|
||||
}
|
||||
|
||||
// Is returns true if any value contains a given message type.
|
||||
func Is(any *any.Any, pb proto.Message) bool {
|
||||
aname, err := AnyMessageName(any)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return aname == proto.MessageName(pb)
|
||||
}
|
||||
191
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
191
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
@@ -1,191 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: google/protobuf/any.proto
|
||||
|
||||
package any // import "github.com/golang/protobuf/ptypes/any"
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||
// URL that describes the type of the serialized message.
|
||||
//
|
||||
// Protobuf library provides support to pack/unpack Any values in the form
|
||||
// of utility functions or additional generated methods of the Any type.
|
||||
//
|
||||
// Example 1: Pack and unpack a message in C++.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any;
|
||||
// any.PackFrom(foo);
|
||||
// ...
|
||||
// if (any.UnpackTo(&foo)) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// Example 2: Pack and unpack a message in Java.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any = Any.pack(foo);
|
||||
// ...
|
||||
// if (any.is(Foo.class)) {
|
||||
// foo = any.unpack(Foo.class);
|
||||
// }
|
||||
//
|
||||
// Example 3: Pack and unpack a message in Python.
|
||||
//
|
||||
// foo = Foo(...)
|
||||
// any = Any()
|
||||
// any.Pack(foo)
|
||||
// ...
|
||||
// if any.Is(Foo.DESCRIPTOR):
|
||||
// any.Unpack(foo)
|
||||
// ...
|
||||
//
|
||||
// Example 4: Pack and unpack a message in Go
|
||||
//
|
||||
// foo := &pb.Foo{...}
|
||||
// any, err := ptypes.MarshalAny(foo)
|
||||
// ...
|
||||
// foo := &pb.Foo{}
|
||||
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// The pack methods provided by protobuf library will by default use
|
||||
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||
// methods only use the fully qualified type name after the last '/'
|
||||
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||
// name "y.z".
|
||||
//
|
||||
//
|
||||
// JSON
|
||||
// ====
|
||||
// The JSON representation of an `Any` value uses the regular
|
||||
// representation of the deserialized, embedded message, with an
|
||||
// additional field `@type` which contains the type URL. Example:
|
||||
//
|
||||
// package google.profile;
|
||||
// message Person {
|
||||
// string first_name = 1;
|
||||
// string last_name = 2;
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.profile.Person",
|
||||
// "firstName": <string>,
|
||||
// "lastName": <string>
|
||||
// }
|
||||
//
|
||||
// If the embedded message type is well-known and has a custom JSON
|
||||
// representation, that representation will be embedded adding a field
|
||||
// `value` which holds the custom JSON in addition to the `@type`
|
||||
// field. Example (for message [google.protobuf.Duration][]):
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||
// "value": "1.212s"
|
||||
// }
|
||||
//
|
||||
type Any struct {
|
||||
// A URL/resource name whose content describes the type of the
|
||||
// serialized protocol buffer message.
|
||||
//
|
||||
// For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||
// following restrictions and interpretations apply:
|
||||
//
|
||||
// * If no scheme is provided, `https` is assumed.
|
||||
// * The last segment of the URL's path must represent the fully
|
||||
// qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||
// The name should be in a canonical form (e.g., leading "." is
|
||||
// not accepted).
|
||||
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||
// value in binary format, or produce an error.
|
||||
// * Applications are allowed to cache lookup results based on the
|
||||
// URL, or have them precompiled into a binary to avoid any
|
||||
// lookup. Therefore, binary compatibility needs to be preserved
|
||||
// on changes to types. (Use versioned type names to manage
|
||||
// breaking changes.)
|
||||
//
|
||||
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||
// used with implementation specific semantics.
|
||||
//
|
||||
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"`
|
||||
// Must be a valid serialized protocol buffer of the above specified type.
|
||||
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Any) Reset() { *m = Any{} }
|
||||
func (m *Any) String() string { return proto.CompactTextString(m) }
|
||||
func (*Any) ProtoMessage() {}
|
||||
func (*Any) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_any_744b9ca530f228db, []int{0}
|
||||
}
|
||||
func (*Any) XXX_WellKnownType() string { return "Any" }
|
||||
func (m *Any) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Any.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Any.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *Any) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Any.Merge(dst, src)
|
||||
}
|
||||
func (m *Any) XXX_Size() int {
|
||||
return xxx_messageInfo_Any.Size(m)
|
||||
}
|
||||
func (m *Any) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Any.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Any proto.InternalMessageInfo
|
||||
|
||||
func (m *Any) GetTypeUrl() string {
|
||||
if m != nil {
|
||||
return m.TypeUrl
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Any) GetValue() []byte {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Any)(nil), "google.protobuf.Any")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_any_744b9ca530f228db) }
|
||||
|
||||
var fileDescriptor_any_744b9ca530f228db = []byte{
|
||||
// 185 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f,
|
||||
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4,
|
||||
0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a,
|
||||
0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46,
|
||||
0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7,
|
||||
0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc2, 0x71, 0xca, 0xe7, 0x12, 0x4e, 0xce,
|
||||
0xcf, 0xd5, 0x43, 0x33, 0xce, 0x89, 0xc3, 0x31, 0xaf, 0x32, 0x00, 0xc4, 0x09, 0x60, 0x8c, 0x52,
|
||||
0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc,
|
||||
0x4b, 0x47, 0xb8, 0xa8, 0x00, 0x64, 0x7a, 0x31, 0xc8, 0x61, 0x8b, 0x98, 0x98, 0xdd, 0x03, 0x9c,
|
||||
0x56, 0x31, 0xc9, 0xb9, 0x43, 0x8c, 0x0a, 0x80, 0x2a, 0xd1, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce,
|
||||
0xcb, 0x2f, 0xcf, 0x0b, 0x01, 0x29, 0x4d, 0x62, 0x03, 0xeb, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff,
|
||||
0xff, 0x13, 0xf8, 0xe8, 0x42, 0xdd, 0x00, 0x00, 0x00,
|
||||
}
|
||||
149
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/any/any.proto
generated
vendored
149
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/any/any.proto
generated
vendored
@@ -1,149 +0,0 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option go_package = "github.com/golang/protobuf/ptypes/any";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "AnyProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||
// URL that describes the type of the serialized message.
|
||||
//
|
||||
// Protobuf library provides support to pack/unpack Any values in the form
|
||||
// of utility functions or additional generated methods of the Any type.
|
||||
//
|
||||
// Example 1: Pack and unpack a message in C++.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any;
|
||||
// any.PackFrom(foo);
|
||||
// ...
|
||||
// if (any.UnpackTo(&foo)) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// Example 2: Pack and unpack a message in Java.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any = Any.pack(foo);
|
||||
// ...
|
||||
// if (any.is(Foo.class)) {
|
||||
// foo = any.unpack(Foo.class);
|
||||
// }
|
||||
//
|
||||
// Example 3: Pack and unpack a message in Python.
|
||||
//
|
||||
// foo = Foo(...)
|
||||
// any = Any()
|
||||
// any.Pack(foo)
|
||||
// ...
|
||||
// if any.Is(Foo.DESCRIPTOR):
|
||||
// any.Unpack(foo)
|
||||
// ...
|
||||
//
|
||||
// Example 4: Pack and unpack a message in Go
|
||||
//
|
||||
// foo := &pb.Foo{...}
|
||||
// any, err := ptypes.MarshalAny(foo)
|
||||
// ...
|
||||
// foo := &pb.Foo{}
|
||||
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// The pack methods provided by protobuf library will by default use
|
||||
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||
// methods only use the fully qualified type name after the last '/'
|
||||
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||
// name "y.z".
|
||||
//
|
||||
//
|
||||
// JSON
|
||||
// ====
|
||||
// The JSON representation of an `Any` value uses the regular
|
||||
// representation of the deserialized, embedded message, with an
|
||||
// additional field `@type` which contains the type URL. Example:
|
||||
//
|
||||
// package google.profile;
|
||||
// message Person {
|
||||
// string first_name = 1;
|
||||
// string last_name = 2;
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.profile.Person",
|
||||
// "firstName": <string>,
|
||||
// "lastName": <string>
|
||||
// }
|
||||
//
|
||||
// If the embedded message type is well-known and has a custom JSON
|
||||
// representation, that representation will be embedded adding a field
|
||||
// `value` which holds the custom JSON in addition to the `@type`
|
||||
// field. Example (for message [google.protobuf.Duration][]):
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||
// "value": "1.212s"
|
||||
// }
|
||||
//
|
||||
message Any {
|
||||
// A URL/resource name whose content describes the type of the
|
||||
// serialized protocol buffer message.
|
||||
//
|
||||
// For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||
// following restrictions and interpretations apply:
|
||||
//
|
||||
// * If no scheme is provided, `https` is assumed.
|
||||
// * The last segment of the URL's path must represent the fully
|
||||
// qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||
// The name should be in a canonical form (e.g., leading "." is
|
||||
// not accepted).
|
||||
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||
// value in binary format, or produce an error.
|
||||
// * Applications are allowed to cache lookup results based on the
|
||||
// URL, or have them precompiled into a binary to avoid any
|
||||
// lookup. Therefore, binary compatibility needs to be preserved
|
||||
// on changes to types. (Use versioned type names to manage
|
||||
// breaking changes.)
|
||||
//
|
||||
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||
// used with implementation specific semantics.
|
||||
//
|
||||
string type_url = 1;
|
||||
|
||||
// Must be a valid serialized protocol buffer of the above specified type.
|
||||
bytes value = 2;
|
||||
}
|
||||
35
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
35
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
Package ptypes contains code for interacting with well-known types.
|
||||
*/
|
||||
package ptypes
|
||||
102
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
102
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
@@ -1,102 +0,0 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package ptypes
|
||||
|
||||
// This file implements conversions between google.protobuf.Duration
|
||||
// and time.Duration.
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
durpb "github.com/golang/protobuf/ptypes/duration"
|
||||
)
|
||||
|
||||
const (
|
||||
// Range of a durpb.Duration in seconds, as specified in
|
||||
// google/protobuf/duration.proto. This is about 10,000 years in seconds.
|
||||
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
|
||||
minSeconds = -maxSeconds
|
||||
)
|
||||
|
||||
// validateDuration determines whether the durpb.Duration is valid according to the
|
||||
// definition in google/protobuf/duration.proto. A valid durpb.Duration
|
||||
// may still be too large to fit into a time.Duration (the range of durpb.Duration
|
||||
// is about 10,000 years, and the range of time.Duration is about 290).
|
||||
func validateDuration(d *durpb.Duration) error {
|
||||
if d == nil {
|
||||
return errors.New("duration: nil Duration")
|
||||
}
|
||||
if d.Seconds < minSeconds || d.Seconds > maxSeconds {
|
||||
return fmt.Errorf("duration: %v: seconds out of range", d)
|
||||
}
|
||||
if d.Nanos <= -1e9 || d.Nanos >= 1e9 {
|
||||
return fmt.Errorf("duration: %v: nanos out of range", d)
|
||||
}
|
||||
// Seconds and Nanos must have the same sign, unless d.Nanos is zero.
|
||||
if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) {
|
||||
return fmt.Errorf("duration: %v: seconds and nanos have different signs", d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Duration converts a durpb.Duration to a time.Duration. Duration
|
||||
// returns an error if the durpb.Duration is invalid or is too large to be
|
||||
// represented in a time.Duration.
|
||||
func Duration(p *durpb.Duration) (time.Duration, error) {
|
||||
if err := validateDuration(p); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d := time.Duration(p.Seconds) * time.Second
|
||||
if int64(d/time.Second) != p.Seconds {
|
||||
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
|
||||
}
|
||||
if p.Nanos != 0 {
|
||||
d += time.Duration(p.Nanos)
|
||||
if (d < 0) != (p.Nanos < 0) {
|
||||
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
|
||||
}
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// DurationProto converts a time.Duration to a durpb.Duration.
|
||||
func DurationProto(d time.Duration) *durpb.Duration {
|
||||
nanos := d.Nanoseconds()
|
||||
secs := nanos / 1e9
|
||||
nanos -= secs * 1e9
|
||||
return &durpb.Duration{
|
||||
Seconds: secs,
|
||||
Nanos: int32(nanos),
|
||||
}
|
||||
}
|
||||
159
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
159
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
@@ -1,159 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: google/protobuf/duration.proto
|
||||
|
||||
package duration // import "github.com/golang/protobuf/ptypes/duration"
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// A Duration represents a signed, fixed-length span of time represented
|
||||
// as a count of seconds and fractions of seconds at nanosecond
|
||||
// resolution. It is independent of any calendar and concepts like "day"
|
||||
// or "month". It is related to Timestamp in that the difference between
|
||||
// two Timestamp values is a Duration and it can be added or subtracted
|
||||
// from a Timestamp. Range is approximately +-10,000 years.
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||
//
|
||||
// Timestamp start = ...;
|
||||
// Timestamp end = ...;
|
||||
// Duration duration = ...;
|
||||
//
|
||||
// duration.seconds = end.seconds - start.seconds;
|
||||
// duration.nanos = end.nanos - start.nanos;
|
||||
//
|
||||
// if (duration.seconds < 0 && duration.nanos > 0) {
|
||||
// duration.seconds += 1;
|
||||
// duration.nanos -= 1000000000;
|
||||
// } else if (durations.seconds > 0 && duration.nanos < 0) {
|
||||
// duration.seconds -= 1;
|
||||
// duration.nanos += 1000000000;
|
||||
// }
|
||||
//
|
||||
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
|
||||
//
|
||||
// Timestamp start = ...;
|
||||
// Duration duration = ...;
|
||||
// Timestamp end = ...;
|
||||
//
|
||||
// end.seconds = start.seconds + duration.seconds;
|
||||
// end.nanos = start.nanos + duration.nanos;
|
||||
//
|
||||
// if (end.nanos < 0) {
|
||||
// end.seconds -= 1;
|
||||
// end.nanos += 1000000000;
|
||||
// } else if (end.nanos >= 1000000000) {
|
||||
// end.seconds += 1;
|
||||
// end.nanos -= 1000000000;
|
||||
// }
|
||||
//
|
||||
// Example 3: Compute Duration from datetime.timedelta in Python.
|
||||
//
|
||||
// td = datetime.timedelta(days=3, minutes=10)
|
||||
// duration = Duration()
|
||||
// duration.FromTimedelta(td)
|
||||
//
|
||||
// # JSON Mapping
|
||||
//
|
||||
// In JSON format, the Duration type is encoded as a string rather than an
|
||||
// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||
// is preceded by the number of seconds, with nanoseconds expressed as
|
||||
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||
// microsecond should be expressed in JSON format as "3.000001s".
|
||||
//
|
||||
//
|
||||
type Duration struct {
|
||||
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
|
||||
// Signed fractions of a second at nanosecond resolution of the span
|
||||
// of time. Durations less than one second are represented with a 0
|
||||
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||
// of one second or more, a non-zero value for the `nanos` field must be
|
||||
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||
// to +999,999,999 inclusive.
|
||||
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Duration) Reset() { *m = Duration{} }
|
||||
func (m *Duration) String() string { return proto.CompactTextString(m) }
|
||||
func (*Duration) ProtoMessage() {}
|
||||
func (*Duration) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_duration_e7d612259e3f0613, []int{0}
|
||||
}
|
||||
func (*Duration) XXX_WellKnownType() string { return "Duration" }
|
||||
func (m *Duration) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Duration.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Duration.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *Duration) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Duration.Merge(dst, src)
|
||||
}
|
||||
func (m *Duration) XXX_Size() int {
|
||||
return xxx_messageInfo_Duration.Size(m)
|
||||
}
|
||||
func (m *Duration) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Duration.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Duration proto.InternalMessageInfo
|
||||
|
||||
func (m *Duration) GetSeconds() int64 {
|
||||
if m != nil {
|
||||
return m.Seconds
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Duration) GetNanos() int32 {
|
||||
if m != nil {
|
||||
return m.Nanos
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Duration)(nil), "google.protobuf.Duration")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_duration_e7d612259e3f0613)
|
||||
}
|
||||
|
||||
var fileDescriptor_duration_e7d612259e3f0613 = []byte{
|
||||
// 190 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f,
|
||||
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a,
|
||||
0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56,
|
||||
0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5,
|
||||
0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e,
|
||||
0x7e, 0xb1, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x6b, 0x10, 0x84, 0xe3, 0x54, 0xc3, 0x25, 0x9c, 0x9c,
|
||||
0x9f, 0xab, 0x87, 0x66, 0xa4, 0x13, 0x2f, 0xcc, 0xc0, 0x00, 0x90, 0x48, 0x00, 0x63, 0x94, 0x56,
|
||||
0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e,
|
||||
0x3a, 0xc2, 0x7d, 0x05, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x70, 0x67, 0xfe, 0x60, 0x64, 0x5c, 0xc4,
|
||||
0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0x62, 0x6e, 0x00, 0x54, 0xa9, 0x5e, 0x78,
|
||||
0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0x48, 0x4b, 0x12, 0x1b, 0xd8, 0x0c, 0x63,
|
||||
0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x84, 0x30, 0xff, 0xf3, 0x00, 0x00, 0x00,
|
||||
}
|
||||
117
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto
generated
vendored
117
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto
generated
vendored
@@ -1,117 +0,0 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "github.com/golang/protobuf/ptypes/duration";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "DurationProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// A Duration represents a signed, fixed-length span of time represented
|
||||
// as a count of seconds and fractions of seconds at nanosecond
|
||||
// resolution. It is independent of any calendar and concepts like "day"
|
||||
// or "month". It is related to Timestamp in that the difference between
|
||||
// two Timestamp values is a Duration and it can be added or subtracted
|
||||
// from a Timestamp. Range is approximately +-10,000 years.
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||
//
|
||||
// Timestamp start = ...;
|
||||
// Timestamp end = ...;
|
||||
// Duration duration = ...;
|
||||
//
|
||||
// duration.seconds = end.seconds - start.seconds;
|
||||
// duration.nanos = end.nanos - start.nanos;
|
||||
//
|
||||
// if (duration.seconds < 0 && duration.nanos > 0) {
|
||||
// duration.seconds += 1;
|
||||
// duration.nanos -= 1000000000;
|
||||
// } else if (durations.seconds > 0 && duration.nanos < 0) {
|
||||
// duration.seconds -= 1;
|
||||
// duration.nanos += 1000000000;
|
||||
// }
|
||||
//
|
||||
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
|
||||
//
|
||||
// Timestamp start = ...;
|
||||
// Duration duration = ...;
|
||||
// Timestamp end = ...;
|
||||
//
|
||||
// end.seconds = start.seconds + duration.seconds;
|
||||
// end.nanos = start.nanos + duration.nanos;
|
||||
//
|
||||
// if (end.nanos < 0) {
|
||||
// end.seconds -= 1;
|
||||
// end.nanos += 1000000000;
|
||||
// } else if (end.nanos >= 1000000000) {
|
||||
// end.seconds += 1;
|
||||
// end.nanos -= 1000000000;
|
||||
// }
|
||||
//
|
||||
// Example 3: Compute Duration from datetime.timedelta in Python.
|
||||
//
|
||||
// td = datetime.timedelta(days=3, minutes=10)
|
||||
// duration = Duration()
|
||||
// duration.FromTimedelta(td)
|
||||
//
|
||||
// # JSON Mapping
|
||||
//
|
||||
// In JSON format, the Duration type is encoded as a string rather than an
|
||||
// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||
// is preceded by the number of seconds, with nanoseconds expressed as
|
||||
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||
// microsecond should be expressed in JSON format as "3.000001s".
|
||||
//
|
||||
//
|
||||
message Duration {
|
||||
|
||||
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||
int64 seconds = 1;
|
||||
|
||||
// Signed fractions of a second at nanosecond resolution of the span
|
||||
// of time. Durations less than one second are represented with a 0
|
||||
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||
// of one second or more, a non-zero value for the `nanos` field must be
|
||||
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||
// to +999,999,999 inclusive.
|
||||
int32 nanos = 2;
|
||||
}
|
||||
134
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
134
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
@@ -1,134 +0,0 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package ptypes
|
||||
|
||||
// This file implements operations on google.protobuf.Timestamp.
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
tspb "github.com/golang/protobuf/ptypes/timestamp"
|
||||
)
|
||||
|
||||
const (
|
||||
// Seconds field of the earliest valid Timestamp.
|
||||
// This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
||||
minValidSeconds = -62135596800
|
||||
// Seconds field just after the latest valid Timestamp.
|
||||
// This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
||||
maxValidSeconds = 253402300800
|
||||
)
|
||||
|
||||
// validateTimestamp determines whether a Timestamp is valid.
|
||||
// A valid timestamp represents a time in the range
|
||||
// [0001-01-01, 10000-01-01) and has a Nanos field
|
||||
// in the range [0, 1e9).
|
||||
//
|
||||
// If the Timestamp is valid, validateTimestamp returns nil.
|
||||
// Otherwise, it returns an error that describes
|
||||
// the problem.
|
||||
//
|
||||
// Every valid Timestamp can be represented by a time.Time, but the converse is not true.
|
||||
func validateTimestamp(ts *tspb.Timestamp) error {
|
||||
if ts == nil {
|
||||
return errors.New("timestamp: nil Timestamp")
|
||||
}
|
||||
if ts.Seconds < minValidSeconds {
|
||||
return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
|
||||
}
|
||||
if ts.Seconds >= maxValidSeconds {
|
||||
return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
|
||||
}
|
||||
if ts.Nanos < 0 || ts.Nanos >= 1e9 {
|
||||
return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Timestamp converts a google.protobuf.Timestamp proto to a time.Time.
|
||||
// It returns an error if the argument is invalid.
|
||||
//
|
||||
// Unlike most Go functions, if Timestamp returns an error, the first return value
|
||||
// is not the zero time.Time. Instead, it is the value obtained from the
|
||||
// time.Unix function when passed the contents of the Timestamp, in the UTC
|
||||
// locale. This may or may not be a meaningful time; many invalid Timestamps
|
||||
// do map to valid time.Times.
|
||||
//
|
||||
// A nil Timestamp returns an error. The first return value in that case is
|
||||
// undefined.
|
||||
func Timestamp(ts *tspb.Timestamp) (time.Time, error) {
|
||||
// Don't return the zero value on error, because corresponds to a valid
|
||||
// timestamp. Instead return whatever time.Unix gives us.
|
||||
var t time.Time
|
||||
if ts == nil {
|
||||
t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
|
||||
} else {
|
||||
t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
|
||||
}
|
||||
return t, validateTimestamp(ts)
|
||||
}
|
||||
|
||||
// TimestampNow returns a google.protobuf.Timestamp for the current time.
|
||||
func TimestampNow() *tspb.Timestamp {
|
||||
ts, err := TimestampProto(time.Now())
|
||||
if err != nil {
|
||||
panic("ptypes: time.Now() out of Timestamp range")
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
|
||||
// It returns an error if the resulting Timestamp is invalid.
|
||||
func TimestampProto(t time.Time) (*tspb.Timestamp, error) {
|
||||
seconds := t.Unix()
|
||||
nanos := int32(t.Sub(time.Unix(seconds, 0)))
|
||||
ts := &tspb.Timestamp{
|
||||
Seconds: seconds,
|
||||
Nanos: nanos,
|
||||
}
|
||||
if err := validateTimestamp(ts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// TimestampString returns the RFC 3339 string for valid Timestamps. For invalid
|
||||
// Timestamps, it returns an error message in parentheses.
|
||||
func TimestampString(ts *tspb.Timestamp) string {
|
||||
t, err := Timestamp(ts)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("(%v)", err)
|
||||
}
|
||||
return t.Format(time.RFC3339Nano)
|
||||
}
|
||||
175
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
175
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
@@ -1,175 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: google/protobuf/timestamp.proto
|
||||
|
||||
package timestamp // import "github.com/golang/protobuf/ptypes/timestamp"
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// A Timestamp represents a point in time independent of any time zone
|
||||
// or calendar, represented as seconds and fractions of seconds at
|
||||
// nanosecond resolution in UTC Epoch time. It is encoded using the
|
||||
// Proleptic Gregorian Calendar which extends the Gregorian calendar
|
||||
// backwards to year one. It is encoded assuming all minutes are 60
|
||||
// seconds long, i.e. leap seconds are "smeared" so that no leap second
|
||||
// table is needed for interpretation. Range is from
|
||||
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
|
||||
// By restricting to that range, we ensure that we can convert to
|
||||
// and from RFC 3339 date strings.
|
||||
// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Example 1: Compute Timestamp from POSIX `time()`.
|
||||
//
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds(time(NULL));
|
||||
// timestamp.set_nanos(0);
|
||||
//
|
||||
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
|
||||
//
|
||||
// struct timeval tv;
|
||||
// gettimeofday(&tv, NULL);
|
||||
//
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds(tv.tv_sec);
|
||||
// timestamp.set_nanos(tv.tv_usec * 1000);
|
||||
//
|
||||
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
|
||||
//
|
||||
// FILETIME ft;
|
||||
// GetSystemTimeAsFileTime(&ft);
|
||||
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||
//
|
||||
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
|
||||
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
|
||||
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
|
||||
//
|
||||
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
|
||||
//
|
||||
// long millis = System.currentTimeMillis();
|
||||
//
|
||||
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
|
||||
// .setNanos((int) ((millis % 1000) * 1000000)).build();
|
||||
//
|
||||
//
|
||||
// Example 5: Compute Timestamp from current time in Python.
|
||||
//
|
||||
// timestamp = Timestamp()
|
||||
// timestamp.GetCurrentTime()
|
||||
//
|
||||
// # JSON Mapping
|
||||
//
|
||||
// In JSON format, the Timestamp type is encoded as a string in the
|
||||
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||
// where {year} is always expressed using four digits while {month}, {day},
|
||||
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||
// is required, though only UTC (as indicated by "Z") is presently supported.
|
||||
//
|
||||
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||
// 01:30 UTC on January 15, 2017.
|
||||
//
|
||||
// In JavaScript, one can convert a Date object to this format using the
|
||||
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
|
||||
// method. In Python, a standard `datetime.datetime` object can be converted
|
||||
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
|
||||
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
|
||||
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
|
||||
// to obtain a formatter capable of generating timestamps in this format.
|
||||
//
|
||||
//
|
||||
type Timestamp struct {
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// inclusive.
|
||||
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Timestamp) Reset() { *m = Timestamp{} }
|
||||
func (m *Timestamp) String() string { return proto.CompactTextString(m) }
|
||||
func (*Timestamp) ProtoMessage() {}
|
||||
func (*Timestamp) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_timestamp_b826e8e5fba671a8, []int{0}
|
||||
}
|
||||
func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" }
|
||||
func (m *Timestamp) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Timestamp.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *Timestamp) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Timestamp.Merge(dst, src)
|
||||
}
|
||||
func (m *Timestamp) XXX_Size() int {
|
||||
return xxx_messageInfo_Timestamp.Size(m)
|
||||
}
|
||||
func (m *Timestamp) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Timestamp.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Timestamp proto.InternalMessageInfo
|
||||
|
||||
func (m *Timestamp) GetSeconds() int64 {
|
||||
if m != nil {
|
||||
return m.Seconds
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Timestamp) GetNanos() int32 {
|
||||
if m != nil {
|
||||
return m.Nanos
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_timestamp_b826e8e5fba671a8)
|
||||
}
|
||||
|
||||
var fileDescriptor_timestamp_b826e8e5fba671a8 = []byte{
|
||||
// 191 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f,
|
||||
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d,
|
||||
0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28,
|
||||
0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5,
|
||||
0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89,
|
||||
0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x53, 0x1d, 0x97, 0x70,
|
||||
0x72, 0x7e, 0xae, 0x1e, 0x9a, 0x99, 0x4e, 0x7c, 0x70, 0x13, 0x03, 0x40, 0x42, 0x01, 0x8c, 0x51,
|
||||
0xda, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89,
|
||||
0x79, 0xe9, 0x08, 0x27, 0x16, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x23, 0x5c, 0xfa, 0x83, 0x91, 0x71,
|
||||
0x11, 0x13, 0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xc9, 0x01, 0x50, 0xb5, 0x7a,
|
||||
0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x3d, 0x49, 0x6c, 0x60, 0x43,
|
||||
0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x77, 0x4a, 0x07, 0xf7, 0x00, 0x00, 0x00,
|
||||
}
|
||||
133
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto
generated
vendored
133
src/cmd/linuxkit/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto
generated
vendored
@@ -1,133 +0,0 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "github.com/golang/protobuf/ptypes/timestamp";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "TimestampProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// A Timestamp represents a point in time independent of any time zone
|
||||
// or calendar, represented as seconds and fractions of seconds at
|
||||
// nanosecond resolution in UTC Epoch time. It is encoded using the
|
||||
// Proleptic Gregorian Calendar which extends the Gregorian calendar
|
||||
// backwards to year one. It is encoded assuming all minutes are 60
|
||||
// seconds long, i.e. leap seconds are "smeared" so that no leap second
|
||||
// table is needed for interpretation. Range is from
|
||||
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
|
||||
// By restricting to that range, we ensure that we can convert to
|
||||
// and from RFC 3339 date strings.
|
||||
// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Example 1: Compute Timestamp from POSIX `time()`.
|
||||
//
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds(time(NULL));
|
||||
// timestamp.set_nanos(0);
|
||||
//
|
||||
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
|
||||
//
|
||||
// struct timeval tv;
|
||||
// gettimeofday(&tv, NULL);
|
||||
//
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds(tv.tv_sec);
|
||||
// timestamp.set_nanos(tv.tv_usec * 1000);
|
||||
//
|
||||
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
|
||||
//
|
||||
// FILETIME ft;
|
||||
// GetSystemTimeAsFileTime(&ft);
|
||||
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||
//
|
||||
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
|
||||
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
|
||||
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
|
||||
//
|
||||
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
|
||||
//
|
||||
// long millis = System.currentTimeMillis();
|
||||
//
|
||||
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
|
||||
// .setNanos((int) ((millis % 1000) * 1000000)).build();
|
||||
//
|
||||
//
|
||||
// Example 5: Compute Timestamp from current time in Python.
|
||||
//
|
||||
// timestamp = Timestamp()
|
||||
// timestamp.GetCurrentTime()
|
||||
//
|
||||
// # JSON Mapping
|
||||
//
|
||||
// In JSON format, the Timestamp type is encoded as a string in the
|
||||
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||
// where {year} is always expressed using four digits while {month}, {day},
|
||||
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||
// is required, though only UTC (as indicated by "Z") is presently supported.
|
||||
//
|
||||
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||
// 01:30 UTC on January 15, 2017.
|
||||
//
|
||||
// In JavaScript, one can convert a Date object to this format using the
|
||||
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
|
||||
// method. In Python, a standard `datetime.datetime` object can be converted
|
||||
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
|
||||
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
|
||||
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
|
||||
// to obtain a formatter capable of generating timestamps in this format.
|
||||
//
|
||||
//
|
||||
message Timestamp {
|
||||
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
int64 seconds = 1;
|
||||
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// inclusive.
|
||||
int32 nanos = 2;
|
||||
}
|
||||
27
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/LICENSE
generated
vendored
27
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/LICENSE
generated
vendored
@@ -1,27 +0,0 @@
|
||||
Copyright 2016, Google Inc.
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
24
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/README.md
generated
vendored
24
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/README.md
generated
vendored
@@ -1,24 +0,0 @@
|
||||
Google API Extensions for Go
|
||||
============================
|
||||
|
||||
[](https://travis-ci.org/googleapis/gax-go)
|
||||
[](https://codecov.io/github/googleapis/gax-go)
|
||||
|
||||
Google API Extensions for Go (gax-go) is a set of modules which aids the
|
||||
development of APIs for clients and servers based on `gRPC` and Google API
|
||||
conventions.
|
||||
|
||||
Application code will rarely need to use this library directly,
|
||||
but the code generated automatically from API definition files can use it
|
||||
to simplify code generation and to provide more convenient and idiomatic API surface.
|
||||
|
||||
**This project is currently experimental and not supported.**
|
||||
|
||||
Go Versions
|
||||
===========
|
||||
This library requires Go 1.6 or above.
|
||||
|
||||
License
|
||||
=======
|
||||
BSD - please see [LICENSE](https://github.com/googleapis/gax-go/blob/master/LICENSE)
|
||||
for more information.
|
||||
136
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/call_option.go
generated
vendored
136
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/call_option.go
generated
vendored
@@ -1,136 +0,0 @@
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package gax
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// CallOption is an option used by Invoke to control behaviors of RPC calls.
|
||||
// CallOption works by modifying relevant fields of CallSettings.
|
||||
type CallOption interface {
|
||||
// Resolve applies the option by modifying cs.
|
||||
Resolve(cs *CallSettings)
|
||||
}
|
||||
|
||||
// Retryer is used by Invoke to determine retry behavior.
|
||||
type Retryer interface {
|
||||
// Retry reports whether a request should be retriedand how long to pause before retrying
|
||||
// if the previous attempt returned with err. Invoke never calls Retry with nil error.
|
||||
Retry(err error) (pause time.Duration, shouldRetry bool)
|
||||
}
|
||||
|
||||
type retryerOption func() Retryer
|
||||
|
||||
func (o retryerOption) Resolve(s *CallSettings) {
|
||||
s.Retry = o
|
||||
}
|
||||
|
||||
// WithRetry sets CallSettings.Retry to fn.
|
||||
func WithRetry(fn func() Retryer) CallOption {
|
||||
return retryerOption(fn)
|
||||
}
|
||||
|
||||
// OnCodes returns a Retryer that retries if and only if
|
||||
// the previous attempt returns a GRPC error whose error code is stored in cc.
|
||||
// Pause times between retries are specified by bo.
|
||||
//
|
||||
// bo is only used for its parameters; each Retryer has its own copy.
|
||||
func OnCodes(cc []codes.Code, bo Backoff) Retryer {
|
||||
return &boRetryer{
|
||||
backoff: bo,
|
||||
codes: append([]codes.Code(nil), cc...),
|
||||
}
|
||||
}
|
||||
|
||||
type boRetryer struct {
|
||||
backoff Backoff
|
||||
codes []codes.Code
|
||||
}
|
||||
|
||||
func (r *boRetryer) Retry(err error) (time.Duration, bool) {
|
||||
c := grpc.Code(err)
|
||||
for _, rc := range r.codes {
|
||||
if c == rc {
|
||||
return r.backoff.Pause(), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Backoff implements exponential backoff.
|
||||
// The wait time between retries is a random value between 0 and the "retry envelope".
|
||||
// The envelope starts at Initial and increases by the factor of Multiplier every retry,
|
||||
// but is capped at Max.
|
||||
type Backoff struct {
|
||||
// Initial is the initial value of the retry envelope, defaults to 1 second.
|
||||
Initial time.Duration
|
||||
|
||||
// Max is the maximum value of the retry envelope, defaults to 30 seconds.
|
||||
Max time.Duration
|
||||
|
||||
// Multiplier is the factor by which the retry envelope increases.
|
||||
// It should be greater than 1 and defaults to 2.
|
||||
Multiplier float64
|
||||
|
||||
// cur is the current retry envelope
|
||||
cur time.Duration
|
||||
}
|
||||
|
||||
func (bo *Backoff) Pause() time.Duration {
|
||||
if bo.Initial == 0 {
|
||||
bo.Initial = time.Second
|
||||
}
|
||||
if bo.cur == 0 {
|
||||
bo.cur = bo.Initial
|
||||
}
|
||||
if bo.Max == 0 {
|
||||
bo.Max = 30 * time.Second
|
||||
}
|
||||
if bo.Multiplier < 1 {
|
||||
bo.Multiplier = 2
|
||||
}
|
||||
d := time.Duration(rand.Int63n(int64(bo.cur)))
|
||||
bo.cur = time.Duration(float64(bo.cur) * bo.Multiplier)
|
||||
if bo.cur > bo.Max {
|
||||
bo.cur = bo.Max
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type CallSettings struct {
|
||||
// Retry returns a Retryer to be used to control retry logic of a method call.
|
||||
// If Retry is nil or the returned Retryer is nil, the call will not be retried.
|
||||
Retry func() Retryer
|
||||
}
|
||||
40
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/gax.go
generated
vendored
40
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/gax.go
generated
vendored
@@ -1,40 +0,0 @@
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Package gax contains a set of modules which aid the development of APIs
|
||||
// for clients and servers based on gRPC and Google API conventions.
|
||||
//
|
||||
// Application code will rarely need to use this library directly.
|
||||
// However, code generated automatically from API definition files can use it
|
||||
// to simplify code generation and to provide more convenient and idiomatic API surfaces.
|
||||
//
|
||||
// This project is currently experimental and not supported.
|
||||
package gax
|
||||
|
||||
const Version = "0.1.0"
|
||||
24
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/header.go
generated
vendored
24
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/header.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
package gax
|
||||
|
||||
import "bytes"
|
||||
|
||||
// XGoogHeader is for use by the Google Cloud Libraries only.
|
||||
//
|
||||
// XGoogHeader formats key-value pairs.
|
||||
// The resulting string is suitable for x-goog-api-client header.
|
||||
func XGoogHeader(keyval ...string) string {
|
||||
if len(keyval) == 0 {
|
||||
return ""
|
||||
}
|
||||
if len(keyval)%2 != 0 {
|
||||
panic("gax.Header: odd argument count")
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < len(keyval); i += 2 {
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(keyval[i])
|
||||
buf.WriteByte('/')
|
||||
buf.WriteString(keyval[i+1])
|
||||
}
|
||||
return buf.String()[1:]
|
||||
}
|
||||
90
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/invoke.go
generated
vendored
90
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/invoke.go
generated
vendored
@@ -1,90 +0,0 @@
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package gax
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// A user defined call stub.
|
||||
type APICall func(context.Context) error
|
||||
|
||||
// Invoke calls the given APICall,
|
||||
// performing retries as specified by opts, if any.
|
||||
func Invoke(ctx context.Context, call APICall, opts ...CallOption) error {
|
||||
var settings CallSettings
|
||||
for _, opt := range opts {
|
||||
opt.Resolve(&settings)
|
||||
}
|
||||
return invoke(ctx, call, settings, Sleep)
|
||||
}
|
||||
|
||||
// Sleep is similar to time.Sleep, but it can be interrupted by ctx.Done() closing.
|
||||
// If interrupted, Sleep returns ctx.Err().
|
||||
func Sleep(ctx context.Context, d time.Duration) error {
|
||||
t := time.NewTimer(d)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
return ctx.Err()
|
||||
case <-t.C:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type sleeper func(ctx context.Context, d time.Duration) error
|
||||
|
||||
// invoke implements Invoke, taking an additional sleeper argument for testing.
|
||||
func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error {
|
||||
var retryer Retryer
|
||||
for {
|
||||
err := call(ctx)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if settings.Retry == nil {
|
||||
return err
|
||||
}
|
||||
if retryer == nil {
|
||||
if r := settings.Retry(); r != nil {
|
||||
retryer = r
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if d, ok := retryer.Retry(err); !ok {
|
||||
return err
|
||||
} else if err = sp(ctx, d); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
176
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/path_template.go
generated
vendored
176
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/path_template.go
generated
vendored
@@ -1,176 +0,0 @@
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package gax
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type matcher interface {
|
||||
match([]string) (int, error)
|
||||
String() string
|
||||
}
|
||||
|
||||
type segment struct {
|
||||
matcher
|
||||
name string
|
||||
}
|
||||
|
||||
type labelMatcher string
|
||||
|
||||
func (ls labelMatcher) match(segments []string) (int, error) {
|
||||
if len(segments) == 0 {
|
||||
return 0, fmt.Errorf("expected %s but no more segments found", ls)
|
||||
}
|
||||
if segments[0] != string(ls) {
|
||||
return 0, fmt.Errorf("expected %s but got %s", ls, segments[0])
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func (ls labelMatcher) String() string {
|
||||
return string(ls)
|
||||
}
|
||||
|
||||
type wildcardMatcher int
|
||||
|
||||
func (wm wildcardMatcher) match(segments []string) (int, error) {
|
||||
if len(segments) == 0 {
|
||||
return 0, errors.New("no more segments found")
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func (wm wildcardMatcher) String() string {
|
||||
return "*"
|
||||
}
|
||||
|
||||
type pathWildcardMatcher int
|
||||
|
||||
func (pwm pathWildcardMatcher) match(segments []string) (int, error) {
|
||||
length := len(segments) - int(pwm)
|
||||
if length <= 0 {
|
||||
return 0, errors.New("not sufficient segments are supplied for path wildcard")
|
||||
}
|
||||
return length, nil
|
||||
}
|
||||
|
||||
func (pwm pathWildcardMatcher) String() string {
|
||||
return "**"
|
||||
}
|
||||
|
||||
type ParseError struct {
|
||||
Pos int
|
||||
Template string
|
||||
Message string
|
||||
}
|
||||
|
||||
func (pe ParseError) Error() string {
|
||||
return fmt.Sprintf("at %d of template '%s', %s", pe.Pos, pe.Template, pe.Message)
|
||||
}
|
||||
|
||||
// PathTemplate manages the template to build and match with paths used
|
||||
// by API services. It holds a template and variable names in it, and
|
||||
// it can extract matched patterns from a path string or build a path
|
||||
// string from a binding.
|
||||
//
|
||||
// See http.proto in github.com/googleapis/googleapis/ for the details of
|
||||
// the template syntax.
|
||||
type PathTemplate struct {
|
||||
segments []segment
|
||||
}
|
||||
|
||||
// NewPathTemplate parses a path template, and returns a PathTemplate
|
||||
// instance if successful.
|
||||
func NewPathTemplate(template string) (*PathTemplate, error) {
|
||||
return parsePathTemplate(template)
|
||||
}
|
||||
|
||||
// MustCompilePathTemplate is like NewPathTemplate but panics if the
|
||||
// expression cannot be parsed. It simplifies safe initialization of
|
||||
// global variables holding compiled regular expressions.
|
||||
func MustCompilePathTemplate(template string) *PathTemplate {
|
||||
pt, err := NewPathTemplate(template)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pt
|
||||
}
|
||||
|
||||
// Match attempts to match the given path with the template, and returns
|
||||
// the mapping of the variable name to the matched pattern string.
|
||||
func (pt *PathTemplate) Match(path string) (map[string]string, error) {
|
||||
paths := strings.Split(path, "/")
|
||||
values := map[string]string{}
|
||||
for _, segment := range pt.segments {
|
||||
length, err := segment.match(paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if segment.name != "" {
|
||||
value := strings.Join(paths[:length], "/")
|
||||
if oldValue, ok := values[segment.name]; ok {
|
||||
values[segment.name] = oldValue + "/" + value
|
||||
} else {
|
||||
values[segment.name] = value
|
||||
}
|
||||
}
|
||||
paths = paths[length:]
|
||||
}
|
||||
if len(paths) != 0 {
|
||||
return nil, fmt.Errorf("Trailing path %s remains after the matching", strings.Join(paths, "/"))
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// Render creates a path string from its template and the binding from
|
||||
// the variable name to the value.
|
||||
func (pt *PathTemplate) Render(binding map[string]string) (string, error) {
|
||||
result := make([]string, 0, len(pt.segments))
|
||||
var lastVariableName string
|
||||
for _, segment := range pt.segments {
|
||||
name := segment.name
|
||||
if lastVariableName != "" && name == lastVariableName {
|
||||
continue
|
||||
}
|
||||
lastVariableName = name
|
||||
if name == "" {
|
||||
result = append(result, segment.String())
|
||||
} else if value, ok := binding[name]; ok {
|
||||
result = append(result, value)
|
||||
} else {
|
||||
return "", fmt.Errorf("%s is not found", name)
|
||||
}
|
||||
}
|
||||
built := strings.Join(result, "/")
|
||||
return built, nil
|
||||
}
|
||||
227
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/path_template_parser.go
generated
vendored
227
src/cmd/linuxkit/vendor/github.com/googleapis/gax-go/path_template_parser.go
generated
vendored
@@ -1,227 +0,0 @@
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package gax
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// This parser follows the syntax of path templates, from
|
||||
// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto.
|
||||
// The differences are that there is no custom verb, we allow the initial slash
|
||||
// to be absent, and that we are not strict as
|
||||
// https://tools.ietf.org/html/rfc6570 about the characters in identifiers and
|
||||
// literals.
|
||||
|
||||
type pathTemplateParser struct {
|
||||
r *strings.Reader
|
||||
runeCount int // the number of the current rune in the original string
|
||||
nextVar int // the number to use for the next unnamed variable
|
||||
seenName map[string]bool // names we've seen already
|
||||
seenPathWildcard bool // have we seen "**" already?
|
||||
}
|
||||
|
||||
func parsePathTemplate(template string) (pt *PathTemplate, err error) {
|
||||
p := &pathTemplateParser{
|
||||
r: strings.NewReader(template),
|
||||
seenName: map[string]bool{},
|
||||
}
|
||||
|
||||
// Handle panics with strings like errors.
|
||||
// See pathTemplateParser.error, below.
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
errmsg, ok := x.(errString)
|
||||
if !ok {
|
||||
panic(x)
|
||||
}
|
||||
pt = nil
|
||||
err = ParseError{p.runeCount, template, string(errmsg)}
|
||||
}
|
||||
}()
|
||||
|
||||
segs := p.template()
|
||||
// If there is a path wildcard, set its length. We can't do this
|
||||
// until we know how many segments we've got all together.
|
||||
for i, seg := range segs {
|
||||
if _, ok := seg.matcher.(pathWildcardMatcher); ok {
|
||||
segs[i].matcher = pathWildcardMatcher(len(segs) - i - 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
return &PathTemplate{segments: segs}, nil
|
||||
|
||||
}
|
||||
|
||||
// Used to indicate errors "thrown" by this parser. We don't use string because
|
||||
// many parts of the standard library panic with strings.
|
||||
type errString string
|
||||
|
||||
// Terminates parsing immediately with an error.
|
||||
func (p *pathTemplateParser) error(msg string) {
|
||||
panic(errString(msg))
|
||||
}
|
||||
|
||||
// Template = [ "/" ] Segments
|
||||
func (p *pathTemplateParser) template() []segment {
|
||||
var segs []segment
|
||||
if p.consume('/') {
|
||||
// Initial '/' needs an initial empty matcher.
|
||||
segs = append(segs, segment{matcher: labelMatcher("")})
|
||||
}
|
||||
return append(segs, p.segments("")...)
|
||||
}
|
||||
|
||||
// Segments = Segment { "/" Segment }
|
||||
func (p *pathTemplateParser) segments(name string) []segment {
|
||||
var segs []segment
|
||||
for {
|
||||
subsegs := p.segment(name)
|
||||
segs = append(segs, subsegs...)
|
||||
if !p.consume('/') {
|
||||
break
|
||||
}
|
||||
}
|
||||
return segs
|
||||
}
|
||||
|
||||
// Segment = "*" | "**" | LITERAL | Variable
|
||||
func (p *pathTemplateParser) segment(name string) []segment {
|
||||
if p.consume('*') {
|
||||
if name == "" {
|
||||
name = fmt.Sprintf("$%d", p.nextVar)
|
||||
p.nextVar++
|
||||
}
|
||||
if p.consume('*') {
|
||||
if p.seenPathWildcard {
|
||||
p.error("multiple '**' disallowed")
|
||||
}
|
||||
p.seenPathWildcard = true
|
||||
// We'll change 0 to the right number at the end.
|
||||
return []segment{{name: name, matcher: pathWildcardMatcher(0)}}
|
||||
}
|
||||
return []segment{{name: name, matcher: wildcardMatcher(0)}}
|
||||
}
|
||||
if p.consume('{') {
|
||||
if name != "" {
|
||||
p.error("recursive named bindings are not allowed")
|
||||
}
|
||||
return p.variable()
|
||||
}
|
||||
return []segment{{name: name, matcher: labelMatcher(p.literal())}}
|
||||
}
|
||||
|
||||
// Variable = "{" FieldPath [ "=" Segments ] "}"
|
||||
// "{" is already consumed.
|
||||
func (p *pathTemplateParser) variable() []segment {
|
||||
// Simplification: treat FieldPath as LITERAL, instead of IDENT { '.' IDENT }
|
||||
name := p.literal()
|
||||
if p.seenName[name] {
|
||||
p.error(name + " appears multiple times")
|
||||
}
|
||||
p.seenName[name] = true
|
||||
var segs []segment
|
||||
if p.consume('=') {
|
||||
segs = p.segments(name)
|
||||
} else {
|
||||
// "{var}" is equivalent to "{var=*}"
|
||||
segs = []segment{{name: name, matcher: wildcardMatcher(0)}}
|
||||
}
|
||||
if !p.consume('}') {
|
||||
p.error("expected '}'")
|
||||
}
|
||||
return segs
|
||||
}
|
||||
|
||||
// A literal is any sequence of characters other than a few special ones.
|
||||
// The list of stop characters is not quite the same as in the template RFC.
|
||||
func (p *pathTemplateParser) literal() string {
|
||||
lit := p.consumeUntil("/*}{=")
|
||||
if lit == "" {
|
||||
p.error("empty literal")
|
||||
}
|
||||
return lit
|
||||
}
|
||||
|
||||
// Read runes until EOF or one of the runes in stopRunes is encountered.
|
||||
// If the latter, unread the stop rune. Return the accumulated runes as a string.
|
||||
func (p *pathTemplateParser) consumeUntil(stopRunes string) string {
|
||||
var runes []rune
|
||||
for {
|
||||
r, ok := p.readRune()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
if strings.IndexRune(stopRunes, r) >= 0 {
|
||||
p.unreadRune()
|
||||
break
|
||||
}
|
||||
runes = append(runes, r)
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// If the next rune is r, consume it and return true.
|
||||
// Otherwise, leave the input unchanged and return false.
|
||||
func (p *pathTemplateParser) consume(r rune) bool {
|
||||
rr, ok := p.readRune()
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if r == rr {
|
||||
return true
|
||||
}
|
||||
p.unreadRune()
|
||||
return false
|
||||
}
|
||||
|
||||
// Read the next rune from the input. Return it.
|
||||
// The second return value is false at EOF.
|
||||
func (p *pathTemplateParser) readRune() (rune, bool) {
|
||||
r, _, err := p.r.ReadRune()
|
||||
if err == io.EOF {
|
||||
return r, false
|
||||
}
|
||||
if err != nil {
|
||||
p.error(err.Error())
|
||||
}
|
||||
p.runeCount++
|
||||
return r, true
|
||||
}
|
||||
|
||||
// Put the last rune that was read back on the input.
|
||||
func (p *pathTemplateParser) unreadRune() {
|
||||
if err := p.r.UnreadRune(); err != nil {
|
||||
p.error(err.Error())
|
||||
}
|
||||
p.runeCount--
|
||||
}
|
||||
16
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/LICENSE
generated
vendored
Normal file
16
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
Unless explicitly stated at the top of the file, this code is covered
|
||||
by the following license:
|
||||
|
||||
Copyright 2016-2017 The authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
100
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/README.md
generated
vendored
Normal file
100
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/README.md
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
This repository contains Go bindings and sample code for [Hyper-V sockets](https://msdn.microsoft.com/en-us/virtualization/hyperv_on_windows/develop/make_mgmt_service) and [virtio sockets](http://stefanha.github.io/virtio/)(VSOCK).
|
||||
|
||||
## Organisation
|
||||
|
||||
- `pkg/hvsock`: Go binding for Hyper-V sockets
|
||||
- `pkg/vsock`: Go binding for virtio VSOCK
|
||||
- `cmd/sock_stress`: A stress test program for virtsock
|
||||
- `cmd/vsudd`: A unix domain socket to virtsock proxy (used in Docker for Mac/Windows)
|
||||
- `scripts`: Miscellaneous scripts
|
||||
- `c`: Sample C code (including benchmarks and stress tests)
|
||||
- `data`: Data from benchmarks
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
By default the Go sample code is build in a container. Simply type `make`.
|
||||
|
||||
If you want to build binaries on a local system use `make build-binaries`.
|
||||
|
||||
## Testing
|
||||
|
||||
There are several examples and tests written both in [Go](./cmd) and in [C](./c). The C code is Hyper-V sockets specific while the Go code also works with virtio sockets and [HyperKit](https://github.com/moby/hyperkit). The respective READMEs contain instructions on how to run the tests, but the simplest way is to use [LinuxKit](https://github.com/linuxkit/linuxkit).
|
||||
|
||||
Assuming you have LinuxKit installed, the make target `make linuxkit`
|
||||
will build a custom Linux image which can be booted on HyperKit or on
|
||||
Windows. The custom Linux image contains the test binaries.
|
||||
|
||||
### macOS
|
||||
|
||||
Boot the Linux VM:
|
||||
```
|
||||
linuxkit run hvtest
|
||||
```
|
||||
This should create a directory called `./hvtest-state`.
|
||||
|
||||
Run the server in the VM and client on the host:
|
||||
```
|
||||
linux$ sock_stress -s vsock -v 1
|
||||
macos$ ./bin/sock_stress.darwin -c vsock://3 -m hyperkit:./hvtest-state -v 1
|
||||
```
|
||||
|
||||
Run the server on the host and the client inside the VM:
|
||||
```
|
||||
macos$ ./bin/sock_stress.darwin -s vsock -m hyperkit:./hvtest-state -v 1
|
||||
linux$ sock_stress -c vsock://2 -v 1
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
On Windows we currently only support the server to be run inside the
|
||||
VM and the host connecting to it. In the future we will support
|
||||
running the server on the host as well.
|
||||
|
||||
For Linux guests on Windows there are two different implmentations,
|
||||
one in the LinuxKit 4.9.x kernels and one in 4.14.x upstream
|
||||
kernels. They require different protocols to be used. The
|
||||
`sock_stress` and `vsudd` programs automatically detect which version
|
||||
to use.
|
||||
|
||||
Boot the Linux VM (from an elevated powershell):
|
||||
```
|
||||
linuxkit run -name hvtest hvtest-efi.iso
|
||||
```
|
||||
|
||||
Run the server in the VM and client on the host:
|
||||
```
|
||||
linux$ sock_stress -v 1 -s hvsock
|
||||
win$ sock_stress -v 1 -c hvsock://<VM ID>
|
||||
```
|
||||
(where `<VM ID>` is from the output of: `(get-vm hvtest).Id`)
|
||||
|
||||
Run the server on the host and the client inside the VM:
|
||||
```
|
||||
win$ sock_stress -v 1 -s hvsock
|
||||
linux$ sock_stress -v 1 -c hvsock://parent
|
||||
```
|
||||
**Note:** This may fail on the client with receiving unexpected EOFs (see below).
|
||||
|
||||
|
||||
## Known limitations
|
||||
|
||||
- `hvsock`: When running the server on the host with a client in a
|
||||
Linux VM, it looks like unidirectional `shutdown()` is not working
|
||||
properly. There appears to be a race of sort.
|
||||
|
||||
- `hvsock`: Hyper-V socket implementations prior to Windows build
|
||||
10586 (aka 1511, aka Threshold 2) was buggy. There may even be
|
||||
issues with build prior to build 14393 (aka 1607, aka Redstone 1).
|
||||
|
||||
- `hvsock`: Earlier versions of this code supported the older Windows
|
||||
builds, but support has now been removed. If you require the older version,
|
||||
please use the `end_10586_tag`.
|
||||
|
||||
- `vsock`: There is general host side implementation as the interface
|
||||
is hypervisor specific. The `vsock` package includes some support
|
||||
for connecting with the VSOCK implementation in
|
||||
[Hyperkit](https://github.com/moby/hyperkit), but there is no
|
||||
implementation for, e.g. `qemu`.
|
||||
|
||||
48
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/README.md
generated
vendored
Normal file
48
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/README.md
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# Hyper-V sockets sample applications
|
||||
|
||||
## Building
|
||||
|
||||
Building is driven by `make` (or `mingw32-make.exe`). By default both
|
||||
Linux and Windows binaries are build.
|
||||
|
||||
Linux builds are done via Dockerfiles and create static binaries.
|
||||
|
||||
Windows builds require MSBuild, Visual Studio and Windows SDK
|
||||
installed with a minimum version of 14290. The project/solutions
|
||||
assumes 14291, so you may have to adjust the
|
||||
`WindowsTargetPlatformVersion` in the project files.
|
||||
|
||||
|
||||
## Running
|
||||
|
||||
All sample application assume a service ID of `3049197C-FACB-11E6-BD58-64006A7986D3` which needs to be registered *once* using:
|
||||
```
|
||||
$service = New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices" -Name 3049197C-FACB-11E6-BD58-64006A7986D3
|
||||
|
||||
$service.SetValue("ElementName", "Hyper-V Socket Echo Service")
|
||||
```
|
||||
|
||||
### Echo applications
|
||||
|
||||
The echo server is started with:
|
||||
```
|
||||
hvecho -s
|
||||
```
|
||||
|
||||
The client supports a number of modes. By default, with no arguments supplied it will connected using loopback mode, i.e. it tries to connect to the server on the same partition:
|
||||
```
|
||||
hvecho -c
|
||||
```
|
||||
|
||||
The client can be run in a VM and started with:
|
||||
```
|
||||
hvecho -c parent
|
||||
```
|
||||
which attempts to connect to the server in the parent partition.
|
||||
|
||||
|
||||
Finally, if the server is run in a VM, the client can be invoked in the parent partition with:
|
||||
```
|
||||
client -c <vmid>
|
||||
```
|
||||
where `<vmid>` is the GUID of the VM the server is running in. The GUID can be retrieved with: `(get-vm <VM Name>).id`.
|
||||
365
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/compat.h
generated
vendored
Normal file
365
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/compat.h
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Compatibility layer between Windows and Linux
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#undef UNICODE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <hvsocket.h>
|
||||
|
||||
#pragma comment (lib, "Ws2_32.lib")
|
||||
#pragma comment (lib, "Mswsock.lib")
|
||||
#pragma comment (lib, "AdvApi32.lib")
|
||||
|
||||
#else /* !_MSC_VER */
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#endif /* !_MSC_VER */
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef int socklen_t;
|
||||
|
||||
typedef __int8 int8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int64 int64_t;
|
||||
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
/* Compat layer for Linux/Unix */
|
||||
typedef int SOCKET;
|
||||
|
||||
#ifndef SOCKET_ERROR
|
||||
#define SOCKET_ERROR -1
|
||||
#endif
|
||||
|
||||
#ifndef INVALID_SOCKET
|
||||
#define INVALID_SOCKET -1
|
||||
#endif
|
||||
|
||||
#define closesocket(_fd) close(_fd)
|
||||
|
||||
/* Shutdown flags are different too */
|
||||
#define SD_SEND SHUT_WR
|
||||
#define SD_RECEIVE SHUT_RD
|
||||
#define SD_BOTH SHUT_RDWR
|
||||
|
||||
#define __cdecl
|
||||
|
||||
/* GUID handling */
|
||||
typedef struct _GUID {
|
||||
uint32_t Data1;
|
||||
uint16_t Data2;
|
||||
uint16_t Data3;
|
||||
uint8_t Data4[8];
|
||||
} GUID;
|
||||
|
||||
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
const GUID name = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}
|
||||
|
||||
|
||||
/* HV Socket definitions */
|
||||
#define AF_HYPERV 43
|
||||
#define HV_PROTOCOL_RAW 1
|
||||
|
||||
typedef struct _SOCKADDR_HV
|
||||
{
|
||||
unsigned short Family;
|
||||
unsigned short Reserved;
|
||||
GUID VmId;
|
||||
GUID ServiceId;
|
||||
} SOCKADDR_HV;
|
||||
|
||||
DEFINE_GUID(HV_GUID_ZERO,
|
||||
0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
DEFINE_GUID(HV_GUID_BROADCAST,
|
||||
0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
|
||||
DEFINE_GUID(HV_GUID_WILDCARD,
|
||||
0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
|
||||
DEFINE_GUID(HV_GUID_CHILDREN,
|
||||
0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd);
|
||||
DEFINE_GUID(HV_GUID_LOOPBACK,
|
||||
0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38);
|
||||
DEFINE_GUID(HV_GUID_PARENT,
|
||||
0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78);
|
||||
|
||||
#endif /* !_MSC_VER */
|
||||
|
||||
/* Common definitions (only valid on Linux, though) */
|
||||
#ifndef AF_VSOCK
|
||||
#define AF_VSOCK 40
|
||||
#endif
|
||||
#ifndef VMADDR_CID_ANY
|
||||
#define VMADDR_CID_ANY -1U
|
||||
#endif
|
||||
#ifndef VMADDR_CID_HYPERVISOR
|
||||
#define VMADDR_CID_HYPERVISOR 0
|
||||
#endif
|
||||
#ifndef VMADDR_CID_RESERVED
|
||||
#define VMADDR_CID_RESERVED 1
|
||||
#endif
|
||||
#ifndef VMADDR_CID_HOST
|
||||
#define VMADDR_CID_HOST 2
|
||||
#endif
|
||||
typedef struct _SOCKADDR_VM
|
||||
{
|
||||
unsigned short Family;
|
||||
unsigned short Reserved;
|
||||
unsigned int SvmPort;
|
||||
unsigned int SvmCID;
|
||||
#ifndef _MSC_VER
|
||||
unsigned char svm_zero[sizeof(struct sockaddr) -
|
||||
sizeof(sa_family_t) - sizeof(unsigned short) -
|
||||
sizeof(unsigned int) - sizeof(unsigned int)];
|
||||
#endif
|
||||
} SOCKADDR_VM;
|
||||
|
||||
|
||||
/* Thread wrappers */
|
||||
#ifdef _MSC_VER
|
||||
typedef HANDLE THREAD_HANDLE;
|
||||
|
||||
static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg)
|
||||
{
|
||||
*t = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, arg, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thread_join(THREAD_HANDLE t)
|
||||
{
|
||||
WaitForSingleObject(t, INFINITE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thread_detach(THREAD_HANDLE t)
|
||||
{
|
||||
return CloseHandle(t);
|
||||
}
|
||||
#else
|
||||
#include <pthread.h>
|
||||
|
||||
typedef pthread_t THREAD_HANDLE;
|
||||
|
||||
static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg)
|
||||
{
|
||||
return pthread_create(t, NULL, f, arg);
|
||||
}
|
||||
|
||||
static inline int thread_join(THREAD_HANDLE t)
|
||||
{
|
||||
return pthread_join(t, NULL);
|
||||
}
|
||||
|
||||
static inline int thread_detach(THREAD_HANDLE t)
|
||||
{
|
||||
return pthread_detach(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Time wrappers */
|
||||
#ifdef _MSC_VER
|
||||
static inline uint64_t time_ns(void)
|
||||
{
|
||||
LARGE_INTEGER t, freq;
|
||||
|
||||
QueryPerformanceFrequency(&freq);
|
||||
QueryPerformanceCounter(&t);
|
||||
|
||||
t.QuadPart *= 1000000000;
|
||||
return (uint64_t)t.QuadPart / freq.QuadPart;
|
||||
}
|
||||
|
||||
static inline unsigned int sleep(unsigned int sec)
|
||||
{
|
||||
Sleep(sec * 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline uint64_t time_ns(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
int ret;
|
||||
|
||||
ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
/* We don't really mind if this overflows...There are plenty of bits */
|
||||
return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Finally some common utility macros and functions
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x"
|
||||
#define GUID_ARGS(_g) \
|
||||
(_g).Data1, (_g).Data2, (_g).Data3, \
|
||||
(_g).Data4[0], (_g).Data4[1], (_g).Data4[2], (_g).Data4[3], \
|
||||
(_g).Data4[4], (_g).Data4[5], (_g).Data4[6], (_g).Data4[7]
|
||||
#define GUID_SARGS(_g) \
|
||||
&(_g).Data1, &(_g).Data2, &(_g).Data3, \
|
||||
&(_g).Data4[0], &(_g).Data4[1], &(_g).Data4[2], &(_g).Data4[3], \
|
||||
&(_g).Data4[4], &(_g).Data4[5], &(_g).Data4[6], &(_g).Data4[7]
|
||||
|
||||
|
||||
static inline int parseguid(const char *s, GUID *g)
|
||||
{
|
||||
int res;
|
||||
int p0, p1, p2, p3, p4, p5, p6, p7;
|
||||
|
||||
res = sscanf(s, GUID_FMT,
|
||||
&g->Data1, &g->Data2, &g->Data3,
|
||||
&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7);
|
||||
if (res != 11)
|
||||
return 1;
|
||||
g->Data4[0] = p0;
|
||||
g->Data4[1] = p1;
|
||||
g->Data4[2] = p2;
|
||||
g->Data4[3] = p3;
|
||||
g->Data4[4] = p4;
|
||||
g->Data4[5] = p5;
|
||||
g->Data4[6] = p6;
|
||||
g->Data4[7] = p7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Slightly different error handling between Windows and Linux */
|
||||
static inline void sockerr(const char *msg)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
fprintf(stderr, "%s Error: %d\n", msg, WSAGetLastError());
|
||||
#else
|
||||
fprintf(stderr, "%s Error: %d. %s\n", msg, errno, strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* poll wrappers */
|
||||
|
||||
/* Set socket to non-blocking */
|
||||
static inline int poll_enable(SOCKET s)
|
||||
{
|
||||
int ret;
|
||||
#ifdef _MSC_VER
|
||||
unsigned long mode = 1;
|
||||
ret = ioctlsocket(s, FIONBIO, &mode);
|
||||
#else
|
||||
int flags;
|
||||
flags = fcntl(s, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
ret = fcntl(s, F_SETFL, flags | O_NONBLOCK);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set socket to non-blocking */
|
||||
static inline int poll_disable(SOCKET s)
|
||||
{
|
||||
int ret;
|
||||
#ifdef _MSC_VER
|
||||
unsigned long mode = 0;
|
||||
ret = ioctlsocket(s, FIONBIO, &mode);
|
||||
#else
|
||||
int flags;
|
||||
flags = fcntl(s, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
ret = fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return true if we should poll */
|
||||
static inline int poll_check()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
int err = WSAGetLastError();
|
||||
return err == WSAEWOULDBLOCK || err == WSAEFAULT;
|
||||
#else
|
||||
return errno == EWOULDBLOCK || errno == EAGAIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static inline int poll(struct pollfd fds[], unsigned long nfds, int timeout)
|
||||
{
|
||||
return WSAPoll(fds, nfds, timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Connect with timeout (in milliseconds), different to WinSock ConnectEx() */
|
||||
static inline int connect_ex(int s, const struct sockaddr *sa,
|
||||
socklen_t len, int timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set fdset;
|
||||
int ret;
|
||||
|
||||
ret = poll_enable(s);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = connect(s, sa, len);
|
||||
if (!ret)
|
||||
goto out; /* Connected */
|
||||
|
||||
/* Got an error, see if we should select() */
|
||||
#ifdef _MSC_VER
|
||||
ret = WSAGetLastError();
|
||||
if (ret != WSAEWOULDBLOCK) {
|
||||
ret = SOCKET_ERROR;
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
if (errno != EINPROGRESS)
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(s, &fdset);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = timeout * 1000;
|
||||
|
||||
ret = select(s + 1, NULL, &fdset, NULL, &tv);
|
||||
if (ret != 1) {
|
||||
ret = SOCKET_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check status */
|
||||
ret = 0;
|
||||
len = sizeof(ret);
|
||||
/* char * is for windows... */
|
||||
getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&ret, &len);
|
||||
if (ret != 0)
|
||||
ret = SOCKET_ERROR;
|
||||
|
||||
out:
|
||||
poll_disable(s);
|
||||
return ret;
|
||||
}
|
||||
552
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/hvbench.c
generated
vendored
Normal file
552
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/hvbench.c
generated
vendored
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* A Hyper-V socket benchmarking program
|
||||
*/
|
||||
#include "compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 3049197C-FACB-11E6-BD58-64006A7986D3 */
|
||||
DEFINE_GUID(BM_GUID,
|
||||
0x3049197c, 0xfacb, 0x11e6, 0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3);
|
||||
#define BM_PORT 0x3049197c
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static WSADATA wsaData;
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(_arr) (sizeof(_arr)/sizeof(*(_arr)))
|
||||
#endif
|
||||
|
||||
/* Use a static buffer for send and receive. */
|
||||
#define MAX_BUF_LEN (2 * 1024 * 1024)
|
||||
static char buf[MAX_BUF_LEN];
|
||||
|
||||
/* Time (in ns) to run eeach bandwidth test */
|
||||
#define BM_BW_TIME (10ULL * 1000 * 1000 * 1000)
|
||||
|
||||
/* How many connections to make */
|
||||
#define BM_CONNS 2000
|
||||
|
||||
static int verbose;
|
||||
#define INFO(...) \
|
||||
do { \
|
||||
if (verbose) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DBG(...) \
|
||||
do { \
|
||||
if (verbose > 1) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TRC(...) \
|
||||
do { \
|
||||
if (verbose > 2) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
enum benchmark {
|
||||
BM_BW_UNI = 1, /* Uni-directional Bandwidth benchamrk */
|
||||
BM_LAT = 2, /* Message ping-pong latency over single connection */
|
||||
BM_CONN = 3, /* Connection benchmark */
|
||||
};
|
||||
|
||||
|
||||
/* There's anecdotal evidence that a blocking send()/recv() is slower
|
||||
* than performing non-blocking send()/recv() calls and then use
|
||||
* epoll()/WSAPoll(). This flags switches between the two
|
||||
*/
|
||||
static int opt_poll;
|
||||
/* Use the vsock interface on Linux */
|
||||
static int opt_vsock;
|
||||
|
||||
|
||||
/* Bandwidth tests:
|
||||
*
|
||||
* The TX side sends a fixed amount of data in fixed sized
|
||||
* messages. The RX side drains the ring in message sized chunks (or less).
|
||||
*/
|
||||
static int bw_rx(SOCKET fd, int msg_sz)
|
||||
{
|
||||
struct pollfd pfd = { 0 };
|
||||
int rx_sz;
|
||||
int ret;
|
||||
|
||||
if (opt_poll) {
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
}
|
||||
|
||||
rx_sz = msg_sz ? msg_sz : ARRAY_SIZE(buf);
|
||||
|
||||
DBG("bw_rx: msg_sz=%d rx_sz=%d\n", msg_sz, rx_sz);
|
||||
|
||||
for (;;) {
|
||||
ret = recv(fd, buf, rx_sz, 0);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
} else if (ret == SOCKET_ERROR) {
|
||||
if (opt_poll && poll_check()) {
|
||||
pfd.revents = 0;
|
||||
poll(&pfd, 1, -1); /* XXX no error checking */
|
||||
continue;
|
||||
}
|
||||
sockerr("recv()");
|
||||
ret = -1;
|
||||
goto err_out;
|
||||
}
|
||||
TRC("Received: %d\n", ret);
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bw_tx(SOCKET fd, int msg_sz, uint64_t *bw)
|
||||
{
|
||||
struct pollfd pfd = { 0 };
|
||||
uint64_t start, end, diff;
|
||||
int msgs_sent = 0;
|
||||
int tx_sz;
|
||||
int sent;
|
||||
int ret;
|
||||
|
||||
if (opt_poll) {
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLOUT;
|
||||
}
|
||||
|
||||
tx_sz = msg_sz ? msg_sz : ARRAY_SIZE(buf);
|
||||
|
||||
DBG("bw_tx: msg_sz=%d tx_sz=%d \n", msg_sz, tx_sz);
|
||||
|
||||
start = time_ns();
|
||||
end = time_ns();
|
||||
|
||||
while (end < start + BM_BW_TIME) {
|
||||
sent = 0;
|
||||
while (sent < tx_sz) {
|
||||
ret = send(fd, buf + sent, tx_sz - sent, 0);
|
||||
if (ret == SOCKET_ERROR) {
|
||||
if (opt_poll && poll_check()) {
|
||||
pfd.revents = 0;
|
||||
poll(&pfd, 1, -1); /* XXX no error checking */
|
||||
continue;
|
||||
}
|
||||
sockerr("send()");
|
||||
ret = -1;
|
||||
goto err_out;
|
||||
}
|
||||
sent += ret;
|
||||
TRC("Sent: %d %d\n", sent, ret);
|
||||
}
|
||||
msgs_sent++;
|
||||
if (!(msgs_sent % 1000))
|
||||
end = time_ns();
|
||||
}
|
||||
DBG("bw_tx: %d %"PRIu64" %"PRIu64"\n", msgs_sent, start, end);
|
||||
|
||||
/* Bandwidth in Mbits per second */
|
||||
diff = end - start;
|
||||
diff /= 1000 * 1000; /* Time in milliseconds */
|
||||
*bw = (8ULL * msgs_sent * msg_sz * 1000) / (diff * 1024 * 1024);
|
||||
ret = 0;
|
||||
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main server and client entry points
|
||||
*/
|
||||
static int server(int bm, int msg_sz)
|
||||
{
|
||||
SOCKET lsock, csock;
|
||||
SOCKADDR_VM savm, sacvm;
|
||||
SOCKADDR_HV sahv, sachv;
|
||||
socklen_t socklen;
|
||||
int max_conn;
|
||||
int ret = 0;
|
||||
|
||||
INFO("server: bm=%d msg_sz=%d\n", bm, msg_sz);
|
||||
|
||||
if (opt_vsock)
|
||||
lsock = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
else
|
||||
lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (lsock == INVALID_SOCKET) {
|
||||
sockerr("socket()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&savm, 0, sizeof(savm));
|
||||
savm.Family = AF_VSOCK;
|
||||
savm.SvmCID = VMADDR_CID_ANY;
|
||||
savm.SvmPort = BM_PORT;
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
sahv.Family = AF_HYPERV;
|
||||
sahv.VmId = HV_GUID_WILDCARD;
|
||||
sahv.ServiceId = BM_GUID;
|
||||
|
||||
if (opt_vsock)
|
||||
ret = bind(lsock, (const struct sockaddr *)&savm, sizeof(savm));
|
||||
else
|
||||
ret = bind(lsock, (const struct sockaddr *)&sahv, sizeof(sahv));
|
||||
if (ret == SOCKET_ERROR) {
|
||||
sockerr("bind()");
|
||||
closesocket(lsock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = listen(lsock, SOMAXCONN);
|
||||
if (ret == SOCKET_ERROR) {
|
||||
sockerr("listen()");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
INFO("server: listening\n");
|
||||
|
||||
if (bm == BM_CONN)
|
||||
max_conn = BM_CONNS;
|
||||
else
|
||||
max_conn = 1;
|
||||
|
||||
while (max_conn) {
|
||||
max_conn--;
|
||||
|
||||
memset(&sacvm, 0, sizeof(sacvm));
|
||||
memset(&sachv, 0, sizeof(sachv));
|
||||
if (opt_vsock) {
|
||||
socklen = sizeof(sacvm);
|
||||
csock = accept(lsock, (struct sockaddr *)&sacvm, &socklen);
|
||||
} else {
|
||||
socklen = sizeof(sachv);
|
||||
csock = accept(lsock, (struct sockaddr *)&sachv, &socklen);
|
||||
}
|
||||
if (csock == INVALID_SOCKET) {
|
||||
sockerr("accept()");
|
||||
ret = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
INFO("server: accepted\n");
|
||||
|
||||
/* Switch to non-blocking if we want to poll */
|
||||
if (opt_poll)
|
||||
poll_enable(csock);
|
||||
|
||||
ret = bw_rx(csock, msg_sz);
|
||||
|
||||
closesocket(csock);
|
||||
}
|
||||
|
||||
err_out:
|
||||
closesocket(lsock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int client(GUID target_guid, unsigned int target_cid,
|
||||
int bm, int msg_sz)
|
||||
{
|
||||
SOCKET fd;
|
||||
SOCKADDR_VM savm;
|
||||
SOCKADDR_HV sahv;
|
||||
uint64_t res;
|
||||
int ret = 0;
|
||||
|
||||
INFO("client: bm=%d msg_sz=%d\n", bm, msg_sz);
|
||||
|
||||
if (opt_vsock)
|
||||
fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
else
|
||||
fd = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (fd == INVALID_SOCKET) {
|
||||
sockerr("socket()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
savm.Family = AF_VSOCK;
|
||||
savm.SvmCID = target_cid;
|
||||
savm.SvmPort = BM_PORT;
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
sahv.Family = AF_HYPERV;
|
||||
sahv.VmId = target_guid;
|
||||
sahv.ServiceId = BM_GUID;
|
||||
|
||||
if (opt_vsock)
|
||||
ret = connect(fd, (const struct sockaddr *)&savm, sizeof(savm));
|
||||
else
|
||||
ret = connect(fd, (const struct sockaddr *)&sahv, sizeof(sahv));
|
||||
if (ret == SOCKET_ERROR) {
|
||||
sockerr("connect()");
|
||||
ret = -1;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
INFO("client: connected\n");
|
||||
|
||||
/* Switch to non-blocking if we want to poll */
|
||||
if (opt_poll)
|
||||
poll_enable(fd);
|
||||
|
||||
if (bm == BM_BW_UNI) {
|
||||
ret = bw_tx(fd, msg_sz, &res);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
printf("%d %"PRIu64"\n", msg_sz, res);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown benchmark %d\n", bm);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
err_out:
|
||||
closesocket(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Different client for connection tests */
|
||||
#define BM_CONN_TIMEOUT 500 /* 500ms */
|
||||
static int client_conn(GUID target_guid, unsigned int target_cid)
|
||||
{
|
||||
uint64_t start, end, diff;
|
||||
int histogram[3 * 9 + 3];
|
||||
SOCKADDR_VM savm;
|
||||
SOCKADDR_HV sahv;
|
||||
SOCKET fd;
|
||||
int sum;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
memset(histogram, 0, sizeof(histogram));
|
||||
|
||||
INFO("client: connection test\n");
|
||||
|
||||
for (i = 0; i < BM_CONNS; i++) {
|
||||
if (opt_vsock)
|
||||
fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
else
|
||||
fd = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (fd == INVALID_SOCKET) {
|
||||
histogram[ARRAY_SIZE(histogram) - 1] += 1;
|
||||
DBG("conn: %d -> socket error\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
savm.Family = AF_VSOCK;
|
||||
savm.SvmCID = target_cid;
|
||||
savm.SvmPort = BM_PORT;
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
sahv.Family = AF_HYPERV;
|
||||
sahv.VmId = target_guid;
|
||||
sahv.ServiceId = BM_GUID;
|
||||
|
||||
start = time_ns();
|
||||
|
||||
if (opt_poll)
|
||||
if (opt_vsock)
|
||||
ret = connect_ex(fd, (const struct sockaddr *)&savm, sizeof(savm),
|
||||
BM_CONN_TIMEOUT);
|
||||
else
|
||||
ret = connect_ex(fd, (const struct sockaddr *)&sahv, sizeof(sahv),
|
||||
BM_CONN_TIMEOUT);
|
||||
else
|
||||
if (opt_vsock)
|
||||
ret = connect(fd, (const struct sockaddr *)&savm, sizeof(savm));
|
||||
else
|
||||
ret = connect(fd, (const struct sockaddr *)&sahv, sizeof(sahv));
|
||||
|
||||
if (ret == SOCKET_ERROR) {
|
||||
histogram[ARRAY_SIZE(histogram) - 2] += 1;
|
||||
DBG("conn: %d -> connect error\n", i);
|
||||
} else {
|
||||
end = time_ns();
|
||||
diff = (end - start);
|
||||
DBG("conn: %d -> %"PRIu64"ns\n", i, diff);
|
||||
|
||||
diff /= (1000 * 1000);
|
||||
if (diff < 10)
|
||||
histogram[diff] += 1;
|
||||
else if (diff < 100)
|
||||
histogram[9 + diff / 10] += 1;
|
||||
else if (diff < 1000)
|
||||
histogram[18 + diff / 100] += 1;
|
||||
else
|
||||
histogram[ARRAY_SIZE(histogram) - 3] += 1;
|
||||
}
|
||||
|
||||
closesocket(fd);
|
||||
}
|
||||
|
||||
/* Print the results */
|
||||
printf("# time (ms) vs count vs cumulative percent\n");
|
||||
sum = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(histogram); i++) {
|
||||
sum += histogram[i];
|
||||
if (i < 9)
|
||||
printf("%d %d %6.2f\n", i + 1, histogram[i],
|
||||
sum * 100.0 / BM_CONNS);
|
||||
else if (i < 18)
|
||||
printf("%d %d %6.2f\n", (i - 9 + 1) * 10, histogram[i],
|
||||
sum * 100.0 / BM_CONNS);
|
||||
else if (i < 27)
|
||||
printf("%d %d %6.2f\n", (i - 18 + 1) * 100, histogram[i],
|
||||
sum * 100.0 / BM_CONNS);
|
||||
else if (i == ARRAY_SIZE(histogram) - 3)
|
||||
printf(">=%d %d %6.2f\n", (i - 27 + 1) * 1000, histogram[i],
|
||||
sum * 100.0 / BM_CONNS);
|
||||
else if (i == ARRAY_SIZE(histogram) - 2)
|
||||
printf("connect_err %d %6.2f\n", histogram[i],
|
||||
sum * 100.0 / BM_CONNS);
|
||||
else
|
||||
printf("socket_err %d %6.2f\n", histogram[i],
|
||||
sum * 100.0 / BM_CONNS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("%s: -s|-c <carg> -b|-l -m <sz> [-v]\n", name);
|
||||
printf(" -s Server mode\n");
|
||||
printf(" -c <carg> Client mode. <carg>:\n");
|
||||
printf(" 'loopback': Connect in loopback mode\n");
|
||||
printf(" 'parent': Connect to the parent partition\n");
|
||||
printf(" <guid>: Connect to VM with GUID\n");
|
||||
printf("\n");
|
||||
printf(" -B Bandwidth test\n");
|
||||
printf(" -L Latency test\n");
|
||||
printf(" -C Connection test\n");
|
||||
printf("\n");
|
||||
printf(" -vsock Use vsock (Linux only)\n");
|
||||
printf(" -m <sz> Message size in bytes\n");
|
||||
printf(" -p Use poll instead of blocking send()/recv()\n");
|
||||
printf(" -v Verbose output\n");
|
||||
}
|
||||
|
||||
int __cdecl main(int argc, char **argv)
|
||||
{
|
||||
int opt_server = 0;
|
||||
int opt_bm = 0;
|
||||
int opt_msgsz = 0;
|
||||
GUID target_guid;
|
||||
unsigned int target_cid;
|
||||
char *target_str = NULL;
|
||||
int res = 0;
|
||||
int i;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Initialize Winsock */
|
||||
res = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "WSAStartup() failed with error: %d\n", res);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No getopt on windows. Do some manual parsing */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-s") == 0) {
|
||||
opt_server = 1;
|
||||
} else if (strcmp(argv[i], "-c") == 0) {
|
||||
opt_server = 0;
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "-c requires an argument\n");
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
if (strcmp(argv[i + 1], "loopback") == 0) {
|
||||
target_guid = HV_GUID_LOOPBACK;
|
||||
target_cid = VMADDR_CID_HYPERVISOR;
|
||||
} else if (strcmp(argv[i + 1], "parent") == 0) {
|
||||
target_guid = HV_GUID_PARENT;
|
||||
target_cid = VMADDR_CID_HOST;
|
||||
} else {
|
||||
target_str = argv[i + 1];
|
||||
}
|
||||
i++;
|
||||
|
||||
} else if (strcmp(argv[i], "-B") == 0) {
|
||||
opt_bm = BM_BW_UNI;
|
||||
} else if (strcmp(argv[i], "-L") == 0) {
|
||||
opt_bm = BM_LAT;
|
||||
} else if (strcmp(argv[i], "-C") == 0) {
|
||||
opt_bm = BM_CONN;
|
||||
|
||||
} else if (strcmp(argv[i], "-vsock") == 0) {
|
||||
opt_vsock = 1;
|
||||
} else if (strcmp(argv[i], "-m") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "-m requires an argument\n");
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
opt_msgsz = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-p") == 0) {
|
||||
opt_poll = 1;
|
||||
} else if (strcmp(argv[i], "-v") == 0) {
|
||||
verbose++;
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
if (opt_vsock) {
|
||||
fprintf(stderr, "-vsock is not valid on Windows\n");
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (target_str) {
|
||||
if (opt_vsock) {
|
||||
target_cid = strtoul(target_str, NULL, 0);
|
||||
} else {
|
||||
res = parseguid(target_str, &target_guid);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "failed to scan: %s\n", target_str);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt_bm) {
|
||||
fprintf(stderr, "You need to specify a test\n");
|
||||
goto out;
|
||||
}
|
||||
if (opt_bm == BM_LAT) {
|
||||
fprintf(stderr, "Latency tests currently not implemented\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_server) {
|
||||
res = server(opt_bm, opt_msgsz);
|
||||
} else {
|
||||
if (opt_bm == BM_CONN)
|
||||
res = client_conn(target_guid, target_cid);
|
||||
else
|
||||
res = client(target_guid, target_cid, opt_bm, opt_msgsz);
|
||||
}
|
||||
|
||||
out:
|
||||
#ifdef _MSC_VER
|
||||
WSACleanup();
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
331
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/hvecho.c
generated
vendored
Normal file
331
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/hvecho.c
generated
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* A simple Echo server and client using Hyper-V sockets
|
||||
*
|
||||
* Works on Linux and Windows (kinda)
|
||||
*
|
||||
* This was primarily written to checkout shutdown(), which turns out
|
||||
* does not work.
|
||||
*/
|
||||
#include "compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 3049197C-FACB-11E6-BD58-64006A7986D3 */
|
||||
DEFINE_GUID(SERVICE_GUID,
|
||||
0x3049197c, 0xfacb, 0x11e6, 0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3);
|
||||
#define SERVICE_PORT 0x3049197c
|
||||
|
||||
#define MY_BUFLEN 4096
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static WSADATA wsaData;
|
||||
#endif
|
||||
|
||||
/* Use the vsock interface on Linux */
|
||||
static int opt_vsock;
|
||||
|
||||
|
||||
/* Handle a connection. Echo back anything sent to us and when the
|
||||
* connection is closed send a bye message.
|
||||
*/
|
||||
static void handle(SOCKET fd)
|
||||
{
|
||||
char recvbuf[MY_BUFLEN];
|
||||
int recvbuflen = MY_BUFLEN;
|
||||
const char *byebuf = "Bye!";
|
||||
int sent;
|
||||
int res;
|
||||
|
||||
do {
|
||||
res = recv(fd, recvbuf, recvbuflen, 0);
|
||||
if (res == 0) {
|
||||
printf("Peer closed\n");
|
||||
break;
|
||||
} else if (res == SOCKET_ERROR) {
|
||||
sockerr("recv()");
|
||||
return;
|
||||
}
|
||||
|
||||
/* No error, echo */
|
||||
printf("Bytes received: %d\n", res);
|
||||
sent = send(fd, recvbuf, res, 0);
|
||||
if (sent == SOCKET_ERROR) {
|
||||
sockerr("send()");
|
||||
return;
|
||||
}
|
||||
printf("Bytes sent: %d\n", sent);
|
||||
|
||||
} while (res > 0);
|
||||
|
||||
/* Send bye */
|
||||
sent = send(fd, byebuf, sizeof(byebuf), 0);
|
||||
if (sent == SOCKET_ERROR) {
|
||||
sockerr("send() bye");
|
||||
return;
|
||||
}
|
||||
printf("Bye Bytes sent: %d\n", sent);
|
||||
}
|
||||
|
||||
|
||||
/* Server:
|
||||
* accept() in an endless loop, handle a connection at a time
|
||||
*/
|
||||
static int server(void)
|
||||
{
|
||||
SOCKET lsock, csock;
|
||||
SOCKADDR_VM savm, sacvm;
|
||||
SOCKADDR_HV sahv, sachv;
|
||||
socklen_t socklen;
|
||||
int res;
|
||||
|
||||
if (opt_vsock)
|
||||
lsock = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
else
|
||||
lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (lsock == INVALID_SOCKET) {
|
||||
sockerr("socket()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&savm, 0, sizeof(savm));
|
||||
savm.Family = AF_VSOCK;
|
||||
savm.SvmCID = VMADDR_CID_ANY;
|
||||
savm.SvmPort = SERVICE_PORT;
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
sahv.Family = AF_HYPERV;
|
||||
sahv.VmId = HV_GUID_WILDCARD;
|
||||
sahv.ServiceId = SERVICE_GUID;
|
||||
|
||||
if (opt_vsock)
|
||||
res = bind(lsock, (const struct sockaddr *)&savm, sizeof(savm));
|
||||
else
|
||||
res = bind(lsock, (const struct sockaddr *)&sahv, sizeof(sahv));
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("bind()");
|
||||
closesocket(lsock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = listen(lsock, SOMAXCONN);
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("listen()");
|
||||
closesocket(lsock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
memset(&sacvm, 0, sizeof(sacvm));
|
||||
memset(&sachv, 0, sizeof(sachv));
|
||||
if (opt_vsock) {
|
||||
socklen = sizeof(sacvm);
|
||||
csock = accept(lsock, (struct sockaddr *)&sacvm, &socklen);
|
||||
} else {
|
||||
socklen = sizeof(sachv);
|
||||
csock = accept(lsock, (struct sockaddr *)&sachv, &socklen);
|
||||
}
|
||||
if (csock == INVALID_SOCKET) {
|
||||
sockerr("accept()");
|
||||
closesocket(lsock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opt_vsock)
|
||||
printf("Connect from: 0x%08x.0x%08x\n", sacvm.SvmCID, sacvm.SvmPort);
|
||||
else
|
||||
printf("Connect from: "GUID_FMT":"GUID_FMT"\n",
|
||||
GUID_ARGS(sachv.VmId), GUID_ARGS(sachv.ServiceId));
|
||||
|
||||
handle(csock);
|
||||
closesocket(csock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The client sends a messages, and waits for the echo before shutting
|
||||
* down the send side. It then expects a bye message from the server.
|
||||
*/
|
||||
static int client(GUID target_guid, unsigned int target_cid)
|
||||
{
|
||||
SOCKET fd = INVALID_SOCKET;
|
||||
SOCKADDR_VM savm;
|
||||
SOCKADDR_HV sahv;
|
||||
char *sendbuf = "this is a test";
|
||||
char recvbuf[MY_BUFLEN];
|
||||
int recvbuflen = MY_BUFLEN;
|
||||
int res;
|
||||
|
||||
if (opt_vsock)
|
||||
fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
else
|
||||
fd = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (fd == INVALID_SOCKET) {
|
||||
sockerr("socket()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
savm.Family = AF_VSOCK;
|
||||
savm.SvmCID = target_cid;
|
||||
savm.SvmPort = SERVICE_PORT;
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
sahv.Family = AF_HYPERV;
|
||||
sahv.VmId = target_guid;
|
||||
sahv.ServiceId = SERVICE_GUID;
|
||||
|
||||
if (opt_vsock) {
|
||||
printf("Connect to: 0x%08x.0x%08x\n", savm.SvmCID, savm.SvmPort);
|
||||
res = connect(fd, (const struct sockaddr *)&savm, sizeof(savm));
|
||||
} else {
|
||||
printf("Connect to: "GUID_FMT":"GUID_FMT"\n",
|
||||
GUID_ARGS(sahv.VmId), GUID_ARGS(sahv.ServiceId));
|
||||
res = connect(fd, (const struct sockaddr *)&sahv, sizeof(sahv));
|
||||
}
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("connect()");
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = send(fd, sendbuf, (int)strlen(sendbuf), 0);
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("send()");
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Bytes Sent: %d\n", res);
|
||||
|
||||
res = recv(fd, recvbuf, recvbuflen, 0);
|
||||
if (res < 0) {
|
||||
sockerr("recv()");
|
||||
goto out;
|
||||
} else if (res == 0) {
|
||||
printf("Connection closed\n");
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Bytes received: %d\n", res);
|
||||
printf("->%s\n", recvbuf);
|
||||
printf("Shutdown\n");
|
||||
|
||||
/* XXX shutdown does not work! */
|
||||
res = shutdown(fd, SD_SEND);
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("shutdown()");
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Wait for bye\n");
|
||||
res = recv(fd, recvbuf, recvbuflen, 0);
|
||||
if (res < 0) {
|
||||
sockerr("recv()");
|
||||
goto out;
|
||||
} else if (res == 0) {
|
||||
printf("Connection closed\n");
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Bytes received: %d\n", res);
|
||||
recvbuf[res] = '\0';
|
||||
printf("->%s\n", recvbuf);
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
closesocket(fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("%s: -s | -c <carg> [-vsock]\n", name);
|
||||
printf(" -s Server mode\n");
|
||||
printf(" -c <carg> Client mode. <carg>:\n");
|
||||
printf(" 'loopback': Connect in loopback mode\n");
|
||||
printf(" 'parent': Connect to the parent partition\n");
|
||||
printf(" <guid>: Connect to VM with GUID\n");
|
||||
printf(" -vsock Use AF_VSOCK (Linux only)\n");
|
||||
}
|
||||
|
||||
int __cdecl main(int argc, char **argv)
|
||||
{
|
||||
int opt_server;
|
||||
int res = 0;
|
||||
GUID target_guid;
|
||||
unsigned int target_cid;
|
||||
char *target_str = NULL;
|
||||
int i;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Initialize Winsock
|
||||
res = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "WSAStartup() failed with error: %d\n", res);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No getopt on windows. Do some manual parsing */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-s") == 0) {
|
||||
opt_server = 1;
|
||||
} else if (strcmp(argv[i], "-c") == 0) {
|
||||
opt_server = 0;
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "-c requires an argument\n");
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
if (strcmp(argv[i + 1], "loopback") == 0) {
|
||||
target_guid = HV_GUID_LOOPBACK;
|
||||
target_cid = VMADDR_CID_HYPERVISOR;
|
||||
} else if (strcmp(argv[i + 1], "parent") == 0) {
|
||||
target_guid = HV_GUID_PARENT;
|
||||
target_cid = VMADDR_CID_HOST;
|
||||
} else {
|
||||
target_str = argv[i + 1];
|
||||
}
|
||||
i++;
|
||||
|
||||
} else if (strcmp(argv[i], "-vsock") == 0) {
|
||||
opt_vsock = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown argument: %s\n", argv[i]);
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
if (opt_vsock) {
|
||||
fprintf(stderr, "-vsock is not valid on Windows\n");
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (target_str) {
|
||||
if (opt_vsock) {
|
||||
target_cid = strtoul(target_str, NULL, 0);
|
||||
} else {
|
||||
res = parseguid(target_str, &target_guid);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "failed to scan: %s\n", target_str);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_server)
|
||||
res = server();
|
||||
else
|
||||
res = client(target_guid, target_cid);
|
||||
|
||||
out:
|
||||
#ifdef _MSC_VER
|
||||
WSACleanup();
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
607
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/hvstress.c
generated
vendored
Normal file
607
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/c/hvstress.c
generated
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* A simple Hyper-V sockets stress test.
|
||||
*
|
||||
* This program uses a configurable number of client threads which all
|
||||
* open a connection to a server and then transfer a random amount of
|
||||
* data to the server which echos the data back.
|
||||
*
|
||||
* The send()/recv() calls optionally alternate between RXTX_BUF_LEN
|
||||
* and RXTX_SMALL_LEN worth of data to add more variability in the
|
||||
* interaction.
|
||||
*/
|
||||
#include "compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 3049197C-FACB-11E6-BD58-64006A7986D3 */
|
||||
DEFINE_GUID(SERVICE_GUID,
|
||||
0x3049197c, 0xfacb, 0x11e6, 0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3);
|
||||
#define SERVICE_PORT 0x3049197c
|
||||
|
||||
/* Maximum amount of data for a single send()/recv() call.
|
||||
* Note: On Windows the maximum length seems to be 8KB and if larger
|
||||
* buffers are passed to send() the connection will be close. We could
|
||||
* use getsockopt(SO_MAX_MSG_SIZE) */
|
||||
#define RXTX_BUF_LEN (4 * 1024)
|
||||
/* Small send()/recv() lengths */
|
||||
#define RXTX_SMALL_LEN 4
|
||||
/* Default number of connections made by the client */
|
||||
#define DEFAULT_CLIENT_CONN 100
|
||||
|
||||
/* Maximum amount of data to send per connection */
|
||||
static int opt_max_len = 20 * 1024 * 1024;
|
||||
/* Global flag to alternate between short and long send()/recv() buffers */
|
||||
static int opt_alternate;
|
||||
/* Use the vsock interface on Linux */
|
||||
static int opt_vsock;
|
||||
|
||||
static int verbose;
|
||||
#define INFO(...) \
|
||||
do { \
|
||||
if (verbose) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DBG(...) \
|
||||
do { \
|
||||
if (verbose > 1) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TRC(...) \
|
||||
do { \
|
||||
if (verbose > 2) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static WSADATA wsaData;
|
||||
#endif
|
||||
|
||||
static unsigned char sendbuf[RXTX_BUF_LEN];
|
||||
|
||||
/* A simple hexdump */
|
||||
static void dump(int id, int conn, const unsigned char *b, int len)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
for (i = 0; i < (len + 16 - 1 - (len - 1) % 16); i += 16) {
|
||||
printf("[%02d:%05d] %04x: ", id, conn, i);
|
||||
for (c = i; c < i + 8; c++)
|
||||
if ( c < len)
|
||||
printf("%02x ", b[c]);
|
||||
printf(" ");
|
||||
for (c = i + 8; c < i + 16; c++)
|
||||
if ( c < len)
|
||||
printf("%02x ", b[c]);
|
||||
printf("\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* Server code
|
||||
*
|
||||
* The server accepts a new connection and spins of a new thread to
|
||||
* handle it. The thread simply echos back the data. We use a thread
|
||||
* per connection because it's simpler code, but ideally we should be
|
||||
* using a pool of worker threads.
|
||||
*/
|
||||
|
||||
/* Arguments to the server thread */
|
||||
struct svr_args {
|
||||
SOCKET fd;
|
||||
int conn;
|
||||
};
|
||||
|
||||
/* Thread entry point for a server */
|
||||
static void *handle(void *a)
|
||||
{
|
||||
struct svr_args *args = a;
|
||||
uint64_t start, end, diff;
|
||||
char recvbuf[RXTX_BUF_LEN];
|
||||
int total_bytes = 0;
|
||||
int rxlen = RXTX_SMALL_LEN;
|
||||
int received;
|
||||
int sent;
|
||||
int res;
|
||||
|
||||
TRC("[%05d] server: handle fd=%d\n", args->conn, (int)args->fd);
|
||||
|
||||
start = time_ns();
|
||||
|
||||
for (;;) {
|
||||
if (opt_alternate)
|
||||
rxlen = (rxlen == RXTX_SMALL_LEN) ? RXTX_BUF_LEN : RXTX_SMALL_LEN;
|
||||
else
|
||||
rxlen = RXTX_BUF_LEN;
|
||||
received = recv(args->fd, recvbuf, rxlen, 0);
|
||||
if (received == 0) {
|
||||
DBG("[%05d] Peer closed\n", args->conn);
|
||||
break;
|
||||
} else if (received == SOCKET_ERROR) {
|
||||
sockerr("recv()");
|
||||
goto out;
|
||||
}
|
||||
TRC("[%05d] server: fd=%d RX %d bytes\n",
|
||||
args->conn, (int)args->fd, received);
|
||||
|
||||
sent = 0;
|
||||
while (sent < received) {
|
||||
res = send(args->fd, recvbuf + sent, received - sent, 0);
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("send()");
|
||||
goto out;
|
||||
}
|
||||
sent += res;
|
||||
TRC("[%05d] server: fd=%d TX %d bytes\n",
|
||||
args->conn, (int)args->fd, res);
|
||||
}
|
||||
total_bytes += sent;
|
||||
}
|
||||
|
||||
end = time_ns();
|
||||
|
||||
out:
|
||||
diff = end - start;
|
||||
diff /= 1000 * 1000;
|
||||
INFO("[%05d] ECHOED: %9d Bytes in %5"PRIu64"ms\n",
|
||||
args->conn, total_bytes, diff);
|
||||
TRC("close(%d)\n", (int)args->fd);
|
||||
closesocket(args->fd);
|
||||
free(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Server entry point */
|
||||
static int server(int multi_threaded, int max_conn)
|
||||
{
|
||||
SOCKET lsock, csock;
|
||||
SOCKADDR_VM savm, sacvm;
|
||||
SOCKADDR_HV sahv, sachv;
|
||||
socklen_t socklen;
|
||||
struct svr_args *args;
|
||||
THREAD_HANDLE st;
|
||||
int conn = 0;
|
||||
int res;
|
||||
|
||||
if (opt_vsock)
|
||||
lsock = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
else
|
||||
lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (lsock == INVALID_SOCKET) {
|
||||
sockerr("socket()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&savm, 0, sizeof(savm));
|
||||
savm.Family = AF_VSOCK;
|
||||
savm.SvmCID = VMADDR_CID_ANY;
|
||||
savm.SvmPort = SERVICE_PORT;
|
||||
|
||||
memset(&sahv, 0, sizeof(sahv));
|
||||
sahv.Family = AF_HYPERV;
|
||||
sahv.VmId = HV_GUID_WILDCARD;
|
||||
sahv.ServiceId = SERVICE_GUID;
|
||||
|
||||
if (opt_vsock)
|
||||
res = bind(lsock, (const struct sockaddr *)&savm, sizeof(savm));
|
||||
else
|
||||
res = bind(lsock, (const struct sockaddr *)&sahv, sizeof(sahv));
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("bind()");
|
||||
closesocket(lsock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = listen(lsock, SOMAXCONN);
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("listen()");
|
||||
closesocket(lsock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
memset(&sacvm, 0, sizeof(sacvm));
|
||||
memset(&sachv, 0, sizeof(sachv));
|
||||
if (opt_vsock) {
|
||||
socklen = sizeof(sacvm);
|
||||
csock = accept(lsock, (struct sockaddr *)&sacvm, &socklen);
|
||||
} else {
|
||||
socklen = sizeof(sachv);
|
||||
csock = accept(lsock, (struct sockaddr *)&sachv, &socklen);
|
||||
}
|
||||
if (csock == INVALID_SOCKET) {
|
||||
sockerr("accept()");
|
||||
closesocket(lsock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opt_vsock)
|
||||
DBG("Connect from: 0x%08x.0x%08x\n", sacvm.SvmCID, sacvm.SvmPort);
|
||||
else
|
||||
DBG("Connect from: "GUID_FMT":"GUID_FMT"\n",
|
||||
GUID_ARGS(sachv.VmId), GUID_ARGS(sachv.ServiceId));
|
||||
|
||||
|
||||
/* Spin up a new thread per connection. Not the most
|
||||
* efficient, but stops us from having to faff about with
|
||||
* worker threads and the like. */
|
||||
args = malloc(sizeof(*args));
|
||||
if (!args) {
|
||||
fprintf(stderr, "failed to malloc thread state\n");
|
||||
return 1;
|
||||
}
|
||||
args->fd = csock;
|
||||
args->conn = conn++;
|
||||
if (multi_threaded) {
|
||||
thread_create(&st, &handle, args);
|
||||
thread_detach(st);
|
||||
} else {
|
||||
handle(args);
|
||||
}
|
||||
|
||||
/* Note, since we are not waiting for thread to finish, this may
|
||||
* cause the last n connections not being handled properly. */
|
||||
if (conn >= max_conn)
|
||||
break;
|
||||
}
|
||||
|
||||
closesocket(lsock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Client code
|
||||
*
|
||||
* The client sends one message of random size and expects the server
|
||||
* to echo it back. The sending is done in a separate thread so we can
|
||||
* simultaneously drain the server's replies. Could do this in a
|
||||
* single thread with poll()/select() as well, but this keeps the code
|
||||
* simpler.
|
||||
*/
|
||||
|
||||
/* Arguments for client threads */
|
||||
struct client_args {
|
||||
THREAD_HANDLE h;
|
||||
GUID target_guid;
|
||||
unsigned int target_cid;
|
||||
int id;
|
||||
int conns;
|
||||
int rand;
|
||||
|
||||
int res;
|
||||
};
|
||||
|
||||
/* Argument passed to Client send thread */
|
||||
struct client_tx_args {
|
||||
SOCKET fd;
|
||||
int tosend;
|
||||
int id;
|
||||
int conn;
|
||||
};
|
||||
|
||||
static void *client_tx(void *a)
|
||||
{
|
||||
struct client_tx_args *args = a;
|
||||
char tmp[128];
|
||||
int tosend, txlen = RXTX_SMALL_LEN;
|
||||
int res;
|
||||
|
||||
tosend = args->tosend;
|
||||
while (tosend) {
|
||||
if (opt_alternate)
|
||||
txlen = (txlen == RXTX_SMALL_LEN) ? RXTX_BUF_LEN : RXTX_SMALL_LEN;
|
||||
else
|
||||
txlen = RXTX_BUF_LEN;
|
||||
txlen = (tosend > txlen) ? txlen : tosend;
|
||||
|
||||
res = send(args->fd, sendbuf, txlen, 0);
|
||||
if (res == SOCKET_ERROR) {
|
||||
snprintf(tmp, sizeof(tmp), "[%02d:%05d] send() after %d bytes",
|
||||
args->id, args->conn, args->tosend - tosend);
|
||||
sockerr(tmp);
|
||||
goto out;
|
||||
}
|
||||
TRC("[%02d:%05d] client: TX %d bytes\n", args->id, args->conn, res);
|
||||
tosend -= res;
|
||||
}
|
||||
DBG("[%02d:%05d] TX: %9d bytes sent\n", args->id, args->conn, args->tosend);
|
||||
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Client code for a single connection */
|
||||
static int client_one(GUID target_guid, unsigned int target_cid,
|
||||
int id, int conn)
|
||||
{
|
||||
struct client_tx_args args;
|
||||
uint64_t start, end, diff;
|
||||
THREAD_HANDLE st;
|
||||
SOCKADDR_VM savm;
|
||||
SOCKADDR_HV sahv;
|
||||
SOCKET fd;
|
||||
unsigned char recvbuf[RXTX_BUF_LEN];
|
||||
int rxlen = RXTX_SMALL_LEN;
|
||||
char tmp[128];
|
||||
int tosend, received = 0;
|
||||
int res;
|
||||
|
||||
TRC("[%02d:%05d] start\n", id, conn);
|
||||
|
||||
start = time_ns();
|
||||
|
||||
if (opt_vsock)
|
||||
fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
else
|
||||
fd = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (fd == INVALID_SOCKET) {
|
||||
sockerr("socket()");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opt_vsock) {
|
||||
savm.Family = AF_VSOCK;
|
||||
savm.SvmCID = target_cid;
|
||||
savm.SvmPort = SERVICE_PORT;
|
||||
DBG("[%02d:%05d] Connected to: 0x%08x.0x%08x fd=%d\n",
|
||||
id, conn, savm.SvmCID, savm.SvmPort, (int)fd);
|
||||
res = connect(fd, (const struct sockaddr *)&savm, sizeof(savm));
|
||||
} else {
|
||||
sahv.Family = AF_HYPERV;
|
||||
sahv.Reserved = 0;
|
||||
sahv.VmId = target_guid;
|
||||
sahv.ServiceId = SERVICE_GUID;
|
||||
DBG("[%02d:%05d] Connected to: "GUID_FMT":"GUID_FMT" fd=%d\n",
|
||||
id, conn, GUID_ARGS(sahv.VmId), GUID_ARGS(sahv.ServiceId), (int)fd);
|
||||
res = connect(fd, (const struct sockaddr *)&sahv, sizeof(sahv));
|
||||
}
|
||||
if (res == SOCKET_ERROR) {
|
||||
sockerr("connect()");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (RAND_MAX < opt_max_len)
|
||||
tosend = (int)((1ULL * RAND_MAX + 1) * rand() + rand());
|
||||
else
|
||||
tosend = rand();
|
||||
|
||||
tosend = tosend % (opt_max_len - 1) + 1;
|
||||
|
||||
DBG("[%02d:%05d] TOSEND: %d bytes\n", id, conn, tosend);
|
||||
args.fd = fd;
|
||||
args.tosend = tosend;
|
||||
args.id = id;
|
||||
args.conn = conn;
|
||||
thread_create(&st, &client_tx, &args);
|
||||
|
||||
while (received < tosend) {
|
||||
if (opt_alternate)
|
||||
rxlen = (rxlen == RXTX_SMALL_LEN) ? RXTX_BUF_LEN : RXTX_SMALL_LEN;
|
||||
else
|
||||
rxlen = RXTX_BUF_LEN;
|
||||
res = recv(fd, recvbuf, rxlen, 0);
|
||||
if (res < 0) {
|
||||
snprintf(tmp, sizeof(tmp), "[%02d:%05d] recv() after %d bytes",
|
||||
id, conn, received);
|
||||
sockerr(tmp);
|
||||
goto thout;
|
||||
} else if (res == 0) {
|
||||
INFO("[%02d:%05d] Connection closed\n", id, conn);
|
||||
res = 1;
|
||||
goto thout;
|
||||
}
|
||||
TRC("[%02d:%05d] client: RX %d bytes\n", id, conn, res);
|
||||
if (verbose > 3)
|
||||
dump(id, conn, recvbuf, res);
|
||||
received += res;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
thout:
|
||||
thread_join(st);
|
||||
end = time_ns();
|
||||
diff = end - start;
|
||||
diff /= 1000 * 1000;
|
||||
INFO("[%02d:%05d] TX/RX: %9d bytes in %5"PRIu64"ms\n",
|
||||
id, conn, received, diff);
|
||||
out:
|
||||
TRC("[%02d:%05d] close(%d)\n", id, conn, (int)fd);
|
||||
closesocket(fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *client_thd(void *a)
|
||||
{
|
||||
struct client_args *args = a;
|
||||
int res, i;
|
||||
|
||||
if (args->rand)
|
||||
srand(time(NULL) + args->id);
|
||||
|
||||
for (i = 0; i < args->conns; i++) {
|
||||
res = client_one(args->target_guid, args->target_cid, args->id, i);
|
||||
if (res)
|
||||
break;
|
||||
}
|
||||
|
||||
args->res = res;
|
||||
return args;
|
||||
}
|
||||
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("%s: -s|-c <carg> [-i <conns>]\n", name);
|
||||
printf(" -s Server mode\n");
|
||||
printf(" -1 "
|
||||
"Use a single thread (handle one connection at a time)\n");
|
||||
printf("\n");
|
||||
printf(" -c <carg> Client mode. <carg>:\n");
|
||||
printf(" 'loopback': Connect in loopback mode\n");
|
||||
printf(" 'parent': Connect to the parent partition\n");
|
||||
printf(" <guid>: Connect to VM with GUID\n");
|
||||
printf(" -p <num> Run 'num' connections in parallel (default 1)\n");
|
||||
printf(" -m <num> Maximum amount of data to send per connection\n");
|
||||
printf(" -r Initialise random number generator with the time\n");
|
||||
printf("\n");
|
||||
printf("Common options\n");
|
||||
printf(" -i <conns> Number connections the client makes (default %d)\n",
|
||||
DEFAULT_CLIENT_CONN);
|
||||
printf(" -vsock Use vsock (Linux only)\n");
|
||||
printf(" -a Alternate using short/long send()/recv() buffers\n");
|
||||
printf(" -v Verbose output (use multiple times)\n");
|
||||
}
|
||||
|
||||
int __cdecl main(int argc, char **argv)
|
||||
{
|
||||
struct client_args *args;
|
||||
int opt_conns = DEFAULT_CLIENT_CONN;
|
||||
int opt_multi_thds = 1;
|
||||
int opt_server = 0;
|
||||
int opt_rand = 0;
|
||||
int opt_par = 1;
|
||||
GUID target_guid;
|
||||
unsigned int target_cid;
|
||||
char *target_str = NULL;
|
||||
int res = 0;
|
||||
int i;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Initialize Winsock */
|
||||
res = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "WSAStartup() failed with error: %d\n", res);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No getopt on windows. Do some manual parsing */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-s") == 0) {
|
||||
opt_server = 1;
|
||||
} else if (strcmp(argv[i], "-c") == 0) {
|
||||
opt_server = 0;
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "-c requires an argument\n");
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
if (strcmp(argv[i + 1], "loopback") == 0) {
|
||||
target_guid = HV_GUID_LOOPBACK;
|
||||
target_cid = VMADDR_CID_HYPERVISOR;
|
||||
} else if (strcmp(argv[i + 1], "parent") == 0) {
|
||||
target_guid = HV_GUID_PARENT;
|
||||
target_cid = VMADDR_CID_HOST;
|
||||
} else {
|
||||
target_str = argv[i + 1];
|
||||
}
|
||||
i++;
|
||||
|
||||
} else if (strcmp(argv[i], "-i") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "-i requires an argument\n");
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
opt_conns = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-p") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "-p requires an argument\n");
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
opt_par = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-m") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "-p requires an argument\n");
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
opt_max_len = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "-r") == 0) {
|
||||
opt_rand = 1;
|
||||
} else if (strcmp(argv[i], "-1") == 0) {
|
||||
opt_multi_thds = 0;
|
||||
} else if (strcmp(argv[i], "-vsock") == 0) {
|
||||
opt_vsock = 1;
|
||||
} else if (strcmp(argv[i], "-a") == 0) {
|
||||
opt_alternate = 1;
|
||||
} else if (strcmp(argv[i], "-v") == 0) {
|
||||
verbose++;
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
if (opt_vsock) {
|
||||
fprintf(stderr, "-vsock is not valid on Windows\n");
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (target_str) {
|
||||
if (opt_vsock) {
|
||||
target_cid = strtoul(target_str, NULL, 0);
|
||||
} else {
|
||||
res = parseguid(target_str, &target_guid);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "failed to scan: %s\n", target_str);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_server) {
|
||||
server(opt_multi_thds, opt_conns);
|
||||
} else {
|
||||
/* Initialise the send buffer with a known pattern */
|
||||
for (i = 0; i < RXTX_BUF_LEN; i++) {
|
||||
if ((i >> 8) % 2)
|
||||
sendbuf[i] = i & 0xff;
|
||||
else
|
||||
sendbuf[i] = 0xff - (i & 0xff);
|
||||
}
|
||||
|
||||
args = calloc(opt_par, sizeof(*args));
|
||||
if (!args) {
|
||||
fprintf(stderr, "failed to malloc");
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Create threads */
|
||||
for (i = 0; i < opt_par; i++) {
|
||||
args[i].target_guid = target_guid;
|
||||
args[i].target_cid = target_cid;
|
||||
args[i].id = i;
|
||||
args[i].conns = opt_conns / opt_par;
|
||||
args[i].rand = opt_rand;
|
||||
thread_create(&args[i].h, &client_thd, &args[i]);
|
||||
}
|
||||
|
||||
/* Wait for threads to finish and collect return codes */
|
||||
res = 0;
|
||||
for (i = 0; i < opt_par; i++) {
|
||||
thread_join(args[i].h);
|
||||
if (args[i].res)
|
||||
fprintf(stderr, "THREAD[%d] failed with %d\n", i, args[i].res);
|
||||
res |= args[i].res;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
#ifdef _MSC_VER
|
||||
WSACleanup();
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
115
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go
generated
vendored
Normal file
115
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
// Package hvsock provides a Go interface to Hyper-V sockets both on
|
||||
// Windows and on Linux. The Linux bindings require patches for the
|
||||
// 4.9.x kernel. If you are using a Linux kernel 4.14.x or newer you
|
||||
// should use the vsock package instead as the Hyper-V socket support
|
||||
// in these kernels have been merged with the virtio sockets
|
||||
// implementation.
|
||||
package hvsock
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
// GUIDZero used by listeners to accept connections from all partitions
|
||||
GUIDZero, _ = GUIDFromString("00000000-0000-0000-0000-000000000000")
|
||||
// GUIDWildcard used by listeners to accept connections from all partitions
|
||||
GUIDWildcard, _ = GUIDFromString("00000000-0000-0000-0000-000000000000")
|
||||
// GUIDBroadcast undocumented
|
||||
GUIDBroadcast, _ = GUIDFromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")
|
||||
// GUIDChildren used by listeners to accept connections from children
|
||||
GUIDChildren, _ = GUIDFromString("90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd")
|
||||
// GUIDLoopback use to connect in loopback mode
|
||||
GUIDLoopback, _ = GUIDFromString("e0e16197-dd56-4a10-9195-5ee7a155a838")
|
||||
// GUIDParent use to connect to the parent partition
|
||||
GUIDParent, _ = GUIDFromString("a42e7cda-d03f-480c-9cc2-a4de20abb878")
|
||||
|
||||
// GUIDs for LinuxVMs with the new Hyper-V socket implementation need to match this template
|
||||
guidTemplate, _ = GUIDFromString("00000000-facb-11e6-bd58-64006a7986d3")
|
||||
)
|
||||
|
||||
const (
|
||||
// The Hyper-V socket implementation used in the 4.9.x kernels
|
||||
// seems to fail silently if messages are above 8k. The newer
|
||||
// implementation in the 4.14.x (and newer) kernels seems to
|
||||
// work fine with larger messages. This is constant is used as
|
||||
// a temporary workaround to limit the amount of data sent and
|
||||
// should be removed once support for 4.9.x kernels is
|
||||
// deprecated.
|
||||
maxMsgSize = 8 * 1024
|
||||
)
|
||||
|
||||
// GUID is used by Hypper-V sockets for "addresses" and "ports"
|
||||
type GUID [16]byte
|
||||
|
||||
// Convert a GUID into a string
|
||||
func (g *GUID) String() string {
|
||||
/* XXX This assume little endian */
|
||||
return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
g[3], g[2], g[1], g[0],
|
||||
g[5], g[4],
|
||||
g[7], g[6],
|
||||
g[8], g[9],
|
||||
g[10], g[11], g[12], g[13], g[14], g[15])
|
||||
}
|
||||
|
||||
// Port converts a Service GUID to a "port" usable by the vsock package.
|
||||
// It can be used to convert hvsock code to vsock code. On 4.14.x
|
||||
// kernels Service GUIDs for talking to Linux should have the form of
|
||||
// xxxxxxxx-facb-11e6-bd58-64006a7986d3, where xxxxxxxx is the vsock port.
|
||||
func (g *GUID) Port() (uint32, error) {
|
||||
// Check that the GUID is as expected
|
||||
if !reflect.DeepEqual(g[4:], guidTemplate[4:]) {
|
||||
return 0, fmt.Errorf("%s does not conform with the template", g)
|
||||
}
|
||||
return binary.LittleEndian.Uint32(g[0:4]), nil
|
||||
}
|
||||
|
||||
// GUIDFromString parses a string and returns a GUID
|
||||
func GUIDFromString(s string) (GUID, error) {
|
||||
var g GUID
|
||||
var err error
|
||||
_, err = fmt.Sscanf(s, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
&g[3], &g[2], &g[1], &g[0],
|
||||
&g[5], &g[4],
|
||||
&g[7], &g[6],
|
||||
&g[8], &g[9],
|
||||
&g[10], &g[11], &g[12], &g[13], &g[14], &g[15])
|
||||
return g, err
|
||||
}
|
||||
|
||||
// Addr represents a Hyper-V socket address
|
||||
type Addr struct {
|
||||
VMID GUID
|
||||
ServiceID GUID
|
||||
}
|
||||
|
||||
// Network returns the type of network for Hyper-V sockets
|
||||
func (a Addr) Network() string {
|
||||
return "hvsock"
|
||||
}
|
||||
|
||||
func (a Addr) String() string {
|
||||
vmid := a.VMID.String()
|
||||
svc := a.ServiceID.String()
|
||||
|
||||
return vmid + ":" + svc
|
||||
}
|
||||
|
||||
// Conn is a hvsock connection which supports half-close.
|
||||
type Conn interface {
|
||||
net.Conn
|
||||
CloseRead() error
|
||||
CloseWrite() error
|
||||
}
|
||||
|
||||
// Since there doesn't seem to be a standard min function
|
||||
func min(x, y int) int {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
22
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go
generated
vendored
Normal file
22
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// +build !linux,!windows
|
||||
|
||||
package hvsock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Supported returns if hvsocks are supported on your platform
|
||||
func Supported() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func Dial(raddr Addr) (Conn, error) {
|
||||
return nil, fmt.Errorf("Dial() not implemented on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
func Listen(addr Addr) (net.Listener, error) {
|
||||
return nil, fmt.Errorf("Listen() not implemented on %s", runtime.GOOS)
|
||||
}
|
||||
262
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go
generated
vendored
Normal file
262
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
package hvsock
|
||||
|
||||
// On Linux we have to deal with two different implementations. The
|
||||
// "legacy" implementation never made it into the kernel, but several
|
||||
// kernels, including the LinuxKit one carried patches for it for
|
||||
// quite a while. The legacy version defined a new address family
|
||||
// while the new version sits on top of the existing VMware/virtio
|
||||
// socket implementation.
|
||||
//
|
||||
// We try to determine at init if we are on a kernel with the legacy
|
||||
// implementation or the new version and set "legacyMode" accordingly.
|
||||
//
|
||||
// We can't just reuse the vsock implementation as we still need to
|
||||
// emulated CloseRead()/CloseWrite() as not all Windows builds support
|
||||
// it.
|
||||
|
||||
/*
|
||||
#include <sys/socket.h>
|
||||
|
||||
struct sockaddr_hv {
|
||||
unsigned short shv_family;
|
||||
unsigned short reserved;
|
||||
unsigned char shv_vm_id[16];
|
||||
unsigned char shv_service_id[16];
|
||||
};
|
||||
int bind_sockaddr_hv(int fd, const struct sockaddr_hv *sa_hv) {
|
||||
return bind(fd, (const struct sockaddr*)sa_hv, sizeof(*sa_hv));
|
||||
}
|
||||
int connect_sockaddr_hv(int fd, const struct sockaddr_hv *sa_hv) {
|
||||
return connect(fd, (const struct sockaddr*)sa_hv, sizeof(*sa_hv));
|
||||
}
|
||||
int accept_hv(int fd, struct sockaddr_hv *sa_hv, socklen_t *sa_hv_len) {
|
||||
return accept4(fd, (struct sockaddr *)sa_hv, sa_hv_len, 0);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
hvsockAF = 43 //SHV_PROTO_RAW
|
||||
hvsockRaw = 1 // SHV_PROTO_RAW
|
||||
)
|
||||
|
||||
// Supported returns if hvsocks are supported on your platform
|
||||
func Supported() bool {
|
||||
// Try opening a hvsockAF socket. If it works we are on older, i.e. 4.9.x kernels.
|
||||
// 4.11 defines AF_SMC as 43 but it doesn't support protocol 1 so the
|
||||
// socket() call should fail.
|
||||
fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
syscall.Close(fd)
|
||||
return true
|
||||
}
|
||||
|
||||
// Dial a Hyper-V socket address
|
||||
func Dial(raddr Addr) (Conn, error) {
|
||||
fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sa := C.struct_sockaddr_hv{}
|
||||
sa.shv_family = hvsockAF
|
||||
sa.reserved = 0
|
||||
|
||||
for i := 0; i < 16; i++ {
|
||||
sa.shv_vm_id[i] = C.uchar(raddr.VMID[i])
|
||||
}
|
||||
for i := 0; i < 16; i++ {
|
||||
sa.shv_service_id[i] = C.uchar(raddr.ServiceID[i])
|
||||
}
|
||||
|
||||
// Retry connect in a loop if EINTR is encountered.
|
||||
for {
|
||||
if ret, errno := C.connect_sockaddr_hv(C.int(fd), &sa); ret != 0 {
|
||||
if errno == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("connect(%s) failed with %d, errno=%d", raddr, ret, errno)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return newHVsockConn(uintptr(fd), &Addr{VMID: GUIDZero, ServiceID: GUIDZero}, &raddr), nil
|
||||
}
|
||||
|
||||
// Listen returns a net.Listener which can accept connections on the given port
|
||||
func Listen(addr Addr) (net.Listener, error) {
|
||||
fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sa := C.struct_sockaddr_hv{}
|
||||
sa.shv_family = hvsockAF
|
||||
sa.reserved = 0
|
||||
|
||||
for i := 0; i < 16; i++ {
|
||||
sa.shv_vm_id[i] = C.uchar(addr.VMID[i])
|
||||
}
|
||||
for i := 0; i < 16; i++ {
|
||||
sa.shv_service_id[i] = C.uchar(addr.ServiceID[i])
|
||||
}
|
||||
|
||||
if ret, errno := C.bind_sockaddr_hv(C.int(fd), &sa); ret != 0 {
|
||||
return nil, fmt.Errorf("listen(%s) failed with %d, errno=%d", addr, ret, errno)
|
||||
}
|
||||
|
||||
err = syscall.Listen(fd, syscall.SOMAXCONN)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "listen(%s) failed", addr)
|
||||
}
|
||||
return &hvsockListener{fd, addr}, nil
|
||||
}
|
||||
|
||||
//
|
||||
// Hyper-v sockets Listener implementation
|
||||
//
|
||||
|
||||
type hvsockListener struct {
|
||||
fd int
|
||||
local Addr
|
||||
}
|
||||
|
||||
// Accept accepts an incoming call and returns the new connection.
|
||||
func (v *hvsockListener) Accept() (net.Conn, error) {
|
||||
var acceptSA C.struct_sockaddr_hv
|
||||
var acceptSALen C.socklen_t
|
||||
|
||||
acceptSALen = C.sizeof_struct_sockaddr_hv
|
||||
fd, err := C.accept_hv(C.int(v.fd), &acceptSA, &acceptSALen)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "accept(%s) failed", v.local)
|
||||
}
|
||||
|
||||
remote := &Addr{VMID: guidFromC(acceptSA.shv_vm_id), ServiceID: guidFromC(acceptSA.shv_service_id)}
|
||||
return newHVsockConn(uintptr(fd), &v.local, remote), nil
|
||||
}
|
||||
|
||||
// Close closes the listening connection
|
||||
func (v *hvsockListener) Close() error {
|
||||
// Note this won't cause the Accept to unblock.
|
||||
return unix.Close(v.fd)
|
||||
}
|
||||
|
||||
// Addr returns the address the Listener is listening on
|
||||
func (v *hvsockListener) Addr() net.Addr {
|
||||
return v.local
|
||||
}
|
||||
|
||||
//
|
||||
// Hyper-V socket connection implementation
|
||||
//
|
||||
|
||||
// hvsockConn represents a connection over a Hyper-V socket
|
||||
type hvsockConn struct {
|
||||
hvsock *os.File
|
||||
fd uintptr
|
||||
local *Addr
|
||||
remote *Addr
|
||||
}
|
||||
|
||||
func newHVsockConn(fd uintptr, local, remote *Addr) *hvsockConn {
|
||||
hvsock := os.NewFile(fd, fmt.Sprintf("hvsock:%d", fd))
|
||||
return &hvsockConn{hvsock: hvsock, fd: fd, local: local, remote: remote}
|
||||
}
|
||||
|
||||
// LocalAddr returns the local address of a connection
|
||||
func (v *hvsockConn) LocalAddr() net.Addr {
|
||||
return v.local
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address of a connection
|
||||
func (v *hvsockConn) RemoteAddr() net.Addr {
|
||||
return v.remote
|
||||
}
|
||||
|
||||
// Close closes the connection
|
||||
func (v *hvsockConn) Close() error {
|
||||
return v.hvsock.Close()
|
||||
}
|
||||
|
||||
// CloseRead shuts down the reading side of a hvsock connection
|
||||
func (v *hvsockConn) CloseRead() error {
|
||||
return syscall.Shutdown(int(v.fd), syscall.SHUT_RD)
|
||||
}
|
||||
|
||||
// CloseWrite shuts down the writing side of a hvsock connection
|
||||
func (v *hvsockConn) CloseWrite() error {
|
||||
return syscall.Shutdown(int(v.fd), syscall.SHUT_WR)
|
||||
}
|
||||
|
||||
// Read reads data from the connection
|
||||
func (v *hvsockConn) Read(buf []byte) (int, error) {
|
||||
return v.hvsock.Read(buf)
|
||||
}
|
||||
|
||||
// Write writes data over the connection
|
||||
// TODO(rn): replace with a straight call to v.hvsock.Write() once 4.9.x support is deprecated
|
||||
func (v *hvsockConn) Write(buf []byte) (int, error) {
|
||||
written := 0
|
||||
toWrite := len(buf)
|
||||
for toWrite > 0 {
|
||||
thisBatch := min(toWrite, maxMsgSize)
|
||||
n, err := v.hvsock.Write(buf[written : written+thisBatch])
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
if n != thisBatch {
|
||||
return written, fmt.Errorf("short write %d != %d", n, thisBatch)
|
||||
}
|
||||
toWrite -= n
|
||||
written += n
|
||||
}
|
||||
|
||||
return written, nil
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines associated with the connection
|
||||
func (v *hvsockConn) SetDeadline(t time.Time) error {
|
||||
return nil // FIXME
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls.
|
||||
func (v *hvsockConn) SetReadDeadline(t time.Time) error {
|
||||
return nil // FIXME
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for future Write calls
|
||||
func (v *hvsockConn) SetWriteDeadline(t time.Time) error {
|
||||
return nil // FIXME
|
||||
}
|
||||
|
||||
// File duplicates the underlying socket descriptor and returns it.
|
||||
func (v *hvsockConn) File() (*os.File, error) {
|
||||
// This is equivalent to dup(2) but creates the new fd with CLOEXEC already set.
|
||||
r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(v.hvsock.Fd()), syscall.F_DUPFD_CLOEXEC, 0)
|
||||
if e1 != 0 {
|
||||
return nil, os.NewSyscallError("fcntl", e1)
|
||||
}
|
||||
return os.NewFile(r0, v.hvsock.Name()), nil
|
||||
}
|
||||
|
||||
func guidFromC(cg [16]C.uchar) GUID {
|
||||
var g GUID
|
||||
for i := 0; i < 16; i++ {
|
||||
g[i] = byte(cg[i])
|
||||
}
|
||||
return g
|
||||
}
|
||||
496
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go
generated
vendored
Normal file
496
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go
generated
vendored
Normal file
@@ -0,0 +1,496 @@
|
||||
package hvsock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Make sure Winsock2 is initialised
|
||||
func init() {
|
||||
e := syscall.WSAStartup(uint32(0x202), &wsaData)
|
||||
if e != nil {
|
||||
log.Fatal("WSAStartup", e)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
hvsockAF = 34 // AF_HYPERV
|
||||
hvsockRaw = 1 // SHV_PROTO_RAW
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrTimeout is an error returned on timeout
|
||||
ErrTimeout = &timeoutError{}
|
||||
|
||||
wsaData syscall.WSAData
|
||||
)
|
||||
|
||||
// Supported returns if hvsocks are supported on your platform
|
||||
func Supported() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Dial a Hyper-V socket address
|
||||
func Dial(raddr Addr) (Conn, error) {
|
||||
fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sa rawSockaddrHyperv
|
||||
ptr, n, err := raddr.sockaddr(&sa)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := sys_connect(fd, ptr, n); err != nil {
|
||||
return nil, errors.Wrapf(err, "connect(%s) failed", raddr)
|
||||
}
|
||||
|
||||
return newHVsockConn(fd, Addr{VMID: GUIDZero, ServiceID: GUIDZero}, raddr)
|
||||
}
|
||||
|
||||
// Listen returns a net.Listener which can accept connections on the given port
|
||||
func Listen(addr Addr) (net.Listener, error) {
|
||||
fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sa rawSockaddrHyperv
|
||||
ptr, n, err := addr.sockaddr(&sa)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := sys_bind(fd, ptr, n); err != nil {
|
||||
return nil, fmt.Errorf("bind(%s) failed with %v", addr, err)
|
||||
}
|
||||
|
||||
err = syscall.Listen(fd, syscall.SOMAXCONN)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "listen(%s) failed", addr)
|
||||
}
|
||||
|
||||
return &hvsockListener{fd, addr}, nil
|
||||
}
|
||||
|
||||
//
|
||||
// Hyper-v sockets Listener implementation
|
||||
//
|
||||
|
||||
type hvsockListener struct {
|
||||
fd syscall.Handle
|
||||
local Addr
|
||||
}
|
||||
|
||||
// Accept accepts an incoming call and returns the new connection
|
||||
func (v *hvsockListener) Accept() (net.Conn, error) {
|
||||
var sa rawSockaddrHyperv
|
||||
var n = int32(unsafe.Sizeof(sa))
|
||||
fd, err := sys_accept(v.fd, &sa, &n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Extract an Addr from sa
|
||||
raddr := Addr{}
|
||||
for i := 0; i < len(raddr.VMID); i++ {
|
||||
raddr.VMID[i] = sa.VMID[i]
|
||||
}
|
||||
for i := 0; i < len(raddr.ServiceID); i++ {
|
||||
raddr.ServiceID[i] = sa.ServiceID[i]
|
||||
}
|
||||
return newHVsockConn(fd, v.local, raddr)
|
||||
}
|
||||
|
||||
// Close closes the listening connection
|
||||
func (v *hvsockListener) Close() error {
|
||||
return syscall.Close(v.fd)
|
||||
}
|
||||
|
||||
// Addr returns the address the Listener is listening on
|
||||
func (v *hvsockListener) Addr() net.Addr {
|
||||
return v.local
|
||||
}
|
||||
|
||||
//
|
||||
// Hyper-V socket connection implementation
|
||||
//
|
||||
|
||||
// hvsockConn represent a Hyper-V connection. Complex mostly due to asynch send()/recv() syscalls.
|
||||
type hvsockConn struct {
|
||||
fd syscall.Handle
|
||||
local Addr
|
||||
remote Addr
|
||||
|
||||
wg sync.WaitGroup
|
||||
wgLock sync.RWMutex
|
||||
closing atomicBool
|
||||
|
||||
readDeadline deadlineHandler
|
||||
writeDeadline deadlineHandler
|
||||
}
|
||||
|
||||
func newHVsockConn(h syscall.Handle, local Addr, remote Addr) (*hvsockConn, error) {
|
||||
ioInitOnce.Do(initIo)
|
||||
v := &hvsockConn{fd: h, local: local, remote: remote}
|
||||
|
||||
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = setFileCompletionNotificationModes(h,
|
||||
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v.readDeadline.channel = make(timeoutChan)
|
||||
v.writeDeadline.channel = make(timeoutChan)
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// LocalAddr returns the local address of a connection
|
||||
func (v *hvsockConn) LocalAddr() net.Addr {
|
||||
return v.local
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address of a connection
|
||||
func (v *hvsockConn) RemoteAddr() net.Addr {
|
||||
return v.remote
|
||||
}
|
||||
|
||||
// Close closes the connection
|
||||
func (v *hvsockConn) Close() error {
|
||||
v.close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseRead shuts down the reading side of a hvsock connection
|
||||
func (v *hvsockConn) CloseRead() error {
|
||||
return syscall.Shutdown(v.fd, syscall.SHUT_RD)
|
||||
}
|
||||
|
||||
// CloseWrite shuts down the writing side of a hvsock connection
|
||||
func (v *hvsockConn) CloseWrite() error {
|
||||
return syscall.Shutdown(v.fd, syscall.SHUT_WR)
|
||||
}
|
||||
|
||||
// Read reads data from the connection
|
||||
func (v *hvsockConn) Read(buf []byte) (int, error) {
|
||||
var b syscall.WSABuf
|
||||
var f uint32
|
||||
|
||||
b.Len = uint32(len(buf))
|
||||
b.Buf = &buf[0]
|
||||
|
||||
c, err := v.prepareIo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer v.wg.Done()
|
||||
|
||||
if v.readDeadline.timedout.isSet() {
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
|
||||
var bytes uint32
|
||||
err = syscall.WSARecv(v.fd, &b, 1, &bytes, &f, &c.o, nil)
|
||||
n, err := v.asyncIo(c, &v.readDeadline, bytes, err)
|
||||
runtime.KeepAlive(buf)
|
||||
|
||||
// Handle EOF conditions.
|
||||
if err == nil && n == 0 && len(buf) != 0 {
|
||||
return 0, io.EOF
|
||||
} else if err == syscall.ERROR_BROKEN_PIPE {
|
||||
return 0, io.EOF
|
||||
} else {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes data over the connection
|
||||
// TODO(rn): Remove once 4.9.x support is deprecated
|
||||
func (v *hvsockConn) Write(buf []byte) (int, error) {
|
||||
written := 0
|
||||
toWrite := len(buf)
|
||||
for toWrite > 0 {
|
||||
thisBatch := min(toWrite, maxMsgSize)
|
||||
n, err := v.write(buf[written : written+thisBatch])
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
if n != thisBatch {
|
||||
return written, fmt.Errorf("short write %d != %d", n, thisBatch)
|
||||
}
|
||||
toWrite -= n
|
||||
written += n
|
||||
}
|
||||
|
||||
return written, nil
|
||||
}
|
||||
|
||||
func (v *hvsockConn) write(buf []byte) (int, error) {
|
||||
var b syscall.WSABuf
|
||||
var f uint32
|
||||
|
||||
if len(buf) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
f = 0
|
||||
b.Len = uint32(len(buf))
|
||||
b.Buf = &buf[0]
|
||||
|
||||
c, err := v.prepareIo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer v.wg.Done()
|
||||
|
||||
if v.writeDeadline.timedout.isSet() {
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
|
||||
var bytes uint32
|
||||
err = syscall.WSASend(v.fd, &b, 1, &bytes, f, &c.o, nil)
|
||||
n, err := v.asyncIo(c, &v.writeDeadline, bytes, err)
|
||||
runtime.KeepAlive(buf)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// SetReadDeadline implementation for Hyper-V sockets
|
||||
func (v *hvsockConn) SetReadDeadline(deadline time.Time) error {
|
||||
return v.readDeadline.set(deadline)
|
||||
}
|
||||
|
||||
// SetWriteDeadline implementation for Hyper-V sockets
|
||||
func (v *hvsockConn) SetWriteDeadline(deadline time.Time) error {
|
||||
return v.writeDeadline.set(deadline)
|
||||
}
|
||||
|
||||
// SetDeadline implementation for Hyper-V sockets
|
||||
func (v *hvsockConn) SetDeadline(deadline time.Time) error {
|
||||
if err := v.SetReadDeadline(deadline); err != nil {
|
||||
return err
|
||||
}
|
||||
return v.SetWriteDeadline(deadline)
|
||||
}
|
||||
|
||||
// Helper functions for conversion to sockaddr
|
||||
|
||||
// struck sockaddr equivalent
|
||||
type rawSockaddrHyperv struct {
|
||||
Family uint16
|
||||
Reserved uint16
|
||||
VMID GUID
|
||||
ServiceID GUID
|
||||
}
|
||||
|
||||
// Utility function to build a struct sockaddr for syscalls.
|
||||
func (a Addr) sockaddr(sa *rawSockaddrHyperv) (unsafe.Pointer, int32, error) {
|
||||
sa.Family = hvsockAF
|
||||
sa.Reserved = 0
|
||||
for i := 0; i < len(sa.VMID); i++ {
|
||||
sa.VMID[i] = a.VMID[i]
|
||||
}
|
||||
for i := 0; i < len(sa.ServiceID); i++ {
|
||||
sa.ServiceID[i] = a.ServiceID[i]
|
||||
}
|
||||
|
||||
return unsafe.Pointer(sa), int32(unsafe.Sizeof(*sa)), nil
|
||||
}
|
||||
|
||||
// Help for read/write timeouts
|
||||
type deadlineHandler struct {
|
||||
setLock sync.Mutex
|
||||
channel timeoutChan
|
||||
channelLock sync.RWMutex
|
||||
timer *time.Timer
|
||||
timedout atomicBool
|
||||
}
|
||||
|
||||
// The code below here is adjusted from:
|
||||
// https://github.com/Microsoft/go-winio/blob/master/file.go
|
||||
type atomicBool int32
|
||||
|
||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
||||
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
||||
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
||||
func (b *atomicBool) swap(new bool) bool {
|
||||
var newInt int32
|
||||
if new {
|
||||
newInt = 1
|
||||
}
|
||||
return atomic.SwapInt32((*int32)(b), newInt) == 1
|
||||
}
|
||||
|
||||
type timeoutError struct{}
|
||||
|
||||
func (e *timeoutError) Error() string { return "i/o timeout" }
|
||||
func (e *timeoutError) Timeout() bool { return true }
|
||||
func (e *timeoutError) Temporary() bool { return true }
|
||||
|
||||
type timeoutChan chan struct{}
|
||||
|
||||
var ioInitOnce sync.Once
|
||||
var ioCompletionPort syscall.Handle
|
||||
|
||||
// ioResult contains the result of an asynchronous IO operation
|
||||
type ioResult struct {
|
||||
bytes uint32
|
||||
err error
|
||||
}
|
||||
|
||||
type ioOperation struct {
|
||||
o syscall.Overlapped
|
||||
ch chan ioResult
|
||||
}
|
||||
|
||||
func initIo() {
|
||||
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ioCompletionPort = h
|
||||
go ioCompletionProcessor(h)
|
||||
}
|
||||
|
||||
func (v *hvsockConn) close() {
|
||||
v.wgLock.Lock()
|
||||
if !v.closing.swap(true) {
|
||||
v.wgLock.Unlock()
|
||||
// cancel all IO and wait for it to complete
|
||||
cancelIoEx(v.fd, nil)
|
||||
v.wg.Wait()
|
||||
// at this point, no new IO can start
|
||||
syscall.Close(v.fd)
|
||||
v.fd = 0
|
||||
} else {
|
||||
v.wgLock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// prepareIo prepares for a new IO operation
|
||||
func (v *hvsockConn) prepareIo() (*ioOperation, error) {
|
||||
v.wgLock.RLock()
|
||||
if v.closing.isSet() {
|
||||
v.wgLock.RUnlock()
|
||||
return nil, fmt.Errorf("HvSocket has already been closed")
|
||||
}
|
||||
v.wg.Add(1)
|
||||
v.wgLock.RUnlock()
|
||||
c := &ioOperation{}
|
||||
c.ch = make(chan ioResult)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ioCompletionProcessor processes completed async IOs forever
|
||||
func ioCompletionProcessor(h syscall.Handle) {
|
||||
// Set the timer resolution to 1. This fixes a performance regression in golang 1.6.
|
||||
timeBeginPeriod(1)
|
||||
for {
|
||||
var bytes uint32
|
||||
var key uintptr
|
||||
var op *ioOperation
|
||||
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
|
||||
if op == nil {
|
||||
panic(err)
|
||||
}
|
||||
op.ch <- ioResult{bytes, err}
|
||||
}
|
||||
}
|
||||
|
||||
// asyncIo processes the return value from Recv or Send, blocking until
|
||||
// the operation has actually completed.
|
||||
func (v *hvsockConn) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
|
||||
if err != syscall.ERROR_IO_PENDING {
|
||||
return int(bytes), err
|
||||
}
|
||||
|
||||
if v.closing.isSet() {
|
||||
cancelIoEx(v.fd, &c.o)
|
||||
}
|
||||
|
||||
var timeout timeoutChan
|
||||
if d != nil {
|
||||
d.channelLock.Lock()
|
||||
timeout = d.channel
|
||||
d.channelLock.Unlock()
|
||||
}
|
||||
|
||||
var r ioResult
|
||||
select {
|
||||
case r = <-c.ch:
|
||||
err = r.err
|
||||
if err == syscall.ERROR_OPERATION_ABORTED {
|
||||
if v.closing.isSet() {
|
||||
err = fmt.Errorf("HvSocket has already been closed")
|
||||
}
|
||||
}
|
||||
case <-timeout:
|
||||
cancelIoEx(v.fd, &c.o)
|
||||
r = <-c.ch
|
||||
err = r.err
|
||||
if err == syscall.ERROR_OPERATION_ABORTED {
|
||||
err = ErrTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// runtime.KeepAlive is needed, as c is passed via native
|
||||
// code to ioCompletionProcessor, c must remain alive
|
||||
// until the channel read is complete.
|
||||
runtime.KeepAlive(c)
|
||||
return int(r.bytes), err
|
||||
}
|
||||
|
||||
func (d *deadlineHandler) set(deadline time.Time) error {
|
||||
d.setLock.Lock()
|
||||
defer d.setLock.Unlock()
|
||||
|
||||
if d.timer != nil {
|
||||
if !d.timer.Stop() {
|
||||
<-d.channel
|
||||
}
|
||||
d.timer = nil
|
||||
}
|
||||
d.timedout.setFalse()
|
||||
|
||||
select {
|
||||
case <-d.channel:
|
||||
d.channelLock.Lock()
|
||||
d.channel = make(chan struct{})
|
||||
d.channelLock.Unlock()
|
||||
default:
|
||||
}
|
||||
|
||||
if deadline.IsZero() {
|
||||
return nil
|
||||
}
|
||||
|
||||
timeoutIO := func() {
|
||||
d.timedout.setTrue()
|
||||
close(d.channel)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
duration := deadline.Sub(now)
|
||||
if deadline.After(now) {
|
||||
// Deadline is in the future, set a timer to wait
|
||||
d.timer = time.AfterFunc(duration, timeoutIO)
|
||||
} else {
|
||||
// Deadline is in the past. Cancel all pending IO now.
|
||||
timeoutIO()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
171
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go
generated
vendored
Normal file
171
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
package hvsock
|
||||
|
||||
/*
|
||||
Most of this code was derived from: https://github.com/Microsoft/go-winio
|
||||
which has the following license:
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Microsoft
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modws2_32 = syscall.NewLazyDLL("ws2_32.dll")
|
||||
modwinmm = syscall.NewLazyDLL("winmm.dll")
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
procConnect = modws2_32.NewProc("connect")
|
||||
procBind = modws2_32.NewProc("bind")
|
||||
procAccept = modws2_32.NewProc("accept")
|
||||
|
||||
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
|
||||
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
|
||||
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
|
||||
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
|
||||
proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod")
|
||||
)
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
socketError = uintptr(^uint32(0))
|
||||
|
||||
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
|
||||
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
func sys_connect(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
|
||||
if r1 == socketError {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func sys_bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procBind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
|
||||
if r1 == socketError {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func sys_accept(s syscall.Handle, rsa *rawSockaddrHyperv, addrlen *int32) (handle syscall.Handle, err error) {
|
||||
r1, _, e1 := syscall.Syscall(procAccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
|
||||
handle = syscall.Handle(r1)
|
||||
if r1 == socketError {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
|
||||
newport = syscall.Handle(r0)
|
||||
if newport == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func timeBeginPeriod(period uint32) (n int32) {
|
||||
r0, _, _ := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0)
|
||||
n = int32(r0)
|
||||
return
|
||||
}
|
||||
24
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/vsock/fallback.go
generated
vendored
Normal file
24
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/vsock/fallback.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// +build !linux,!darwin
|
||||
|
||||
package vsock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
// SocketMode is the unimplemented fallback for unsupported OSes
|
||||
func SocketMode(socketMode string) {
|
||||
log.Fatalln("Unimplemented")
|
||||
}
|
||||
|
||||
// Dial is the unimplemented fallback for unsupported OSes
|
||||
func Dial(cid, port uint32) (Conn, error) {
|
||||
return nil, fmt.Errorf("Unimplemented")
|
||||
}
|
||||
|
||||
// Listen is the unimplemented fallback for unsupported OSes
|
||||
func Listen(cid, port uint32) (net.Listener, error) {
|
||||
return nil, fmt.Errorf("Unimplemented")
|
||||
}
|
||||
66
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/vsock/hyperkit_darwin.go
generated
vendored
Normal file
66
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/vsock/hyperkit_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Package vsock provides bindings to the hyperkit based
|
||||
// implementation on macOS hosts. virtio Sockets are exposed as named
|
||||
// pipes on macOS. Two modes are supported (to be set with
|
||||
// SockerMode()):
|
||||
// - Hyperkit mode: The package needs to be initialised with the path
|
||||
// to where the named pipe was created.
|
||||
// - Docker for Mac mode: This is a shortcut which hard codes the
|
||||
// location of the named pipe.
|
||||
package vsock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
socketPath string
|
||||
connectPath string
|
||||
socketFmt string
|
||||
)
|
||||
|
||||
// SocketMode initialises the bindings to either raw hyperkit mode
|
||||
// ("hyperkit:/path") or Docker for Mac mode ("docker"). This function
|
||||
// must be called before using the vsock bindings.
|
||||
func SocketMode(socketMode string) {
|
||||
socketFmt = "%08x.%08x"
|
||||
|
||||
if strings.HasPrefix(socketMode, "hyperkit:") {
|
||||
socketPath = socketMode[len("hyperkit:"):]
|
||||
} else if socketMode == "docker" {
|
||||
socketPath = filepath.Join(os.Getenv("HOME"), "/Library/Containers/com.docker.docker/Data/vms/0")
|
||||
} else {
|
||||
log.Fatalln("Unknown socket mode: ", socketMode)
|
||||
}
|
||||
|
||||
connectPath = filepath.Join(socketPath, "connect")
|
||||
}
|
||||
|
||||
// Dial creates a connection to the VM with the given client ID and port
|
||||
func Dial(cid, port uint32) (Conn, error) {
|
||||
c, err := net.DialUnix("unix", nil, &net.UnixAddr{connectPath, "unix"})
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "failed to dial on %s", connectPath)
|
||||
}
|
||||
if _, err := fmt.Fprintf(c, "%08x.%08x\n", cid, port); err != nil {
|
||||
return c, errors.Wrapf(err, "Failed to write dest (%08x.%08x) to %s", cid, port, connectPath)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Listen creates a listener for a specifc vsock.
|
||||
func Listen(cid, port uint32) (net.Listener, error) {
|
||||
sock := filepath.Join(socketPath, fmt.Sprintf(socketFmt, cid, port))
|
||||
if err := os.Remove(sock); err != nil && !os.IsNotExist(err) {
|
||||
log.Fatalln("Listen(): Remove:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return net.ListenUnix("unix", &net.UnixAddr{sock, "unix"})
|
||||
}
|
||||
51
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock.go
generated
vendored
Normal file
51
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// Package vsock provides the Linux guest bindings to VM sockets. VM
|
||||
// sockets are a generic mechanism for guest<->host communication. It
|
||||
// was originally developed for VMware but now also supports virtio
|
||||
// sockets and (soon) Hyper-V sockets.
|
||||
//
|
||||
// The main purpose is to provide bindings to the Linux implementation
|
||||
// of VM sockets, based on the low level support in
|
||||
// golang.org/x/sys/unix.
|
||||
//
|
||||
// The package also provides bindings to the host interface to virtio
|
||||
// sockets for HyperKit on macOS.
|
||||
package vsock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
// CIDAny is a wildcard CID
|
||||
CIDAny = 4294967295 // 2^32-1
|
||||
// CIDHypervisor is the reserved CID for the Hypervisor
|
||||
CIDHypervisor = 0
|
||||
// CIDHost is the reserved CID for the host system
|
||||
CIDHost = 2
|
||||
)
|
||||
|
||||
// Addr represents the address of a vsock end point.
|
||||
type Addr struct {
|
||||
CID uint32
|
||||
Port uint32
|
||||
}
|
||||
|
||||
// Network returns the network type for a Addr
|
||||
func (a Addr) Network() string {
|
||||
return "vsock"
|
||||
}
|
||||
|
||||
// String returns a string representation of a Addr
|
||||
func (a Addr) String() string {
|
||||
return fmt.Sprintf("%08x.%08x", a.CID, a.Port)
|
||||
}
|
||||
|
||||
// Conn is a vsock connection which supports half-close.
|
||||
type Conn interface {
|
||||
net.Conn
|
||||
CloseRead() error
|
||||
CloseWrite() error
|
||||
File() (*os.File, error)
|
||||
}
|
||||
164
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock_linux.go
generated
vendored
Normal file
164
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock_linux.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
// Bindings to the Linux hues interface to VM sockets.
|
||||
|
||||
package vsock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// SocketMode is a NOOP on Linux
|
||||
func SocketMode(m string) {
|
||||
}
|
||||
|
||||
// Convert a generic unix.Sockaddr to a Addr
|
||||
func sockaddrToVsock(sa unix.Sockaddr) *Addr {
|
||||
switch sa := sa.(type) {
|
||||
case *unix.SockaddrVM:
|
||||
return &Addr{CID: sa.CID, Port: sa.Port}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dial connects to the CID.Port via virtio sockets
|
||||
func Dial(cid, port uint32) (Conn, error) {
|
||||
fd, err := syscall.Socket(unix.AF_VSOCK, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to create AF_VSOCK socket")
|
||||
}
|
||||
sa := &unix.SockaddrVM{CID: cid, Port: port}
|
||||
// Retry connect in a loop if EINTR is encountered.
|
||||
for {
|
||||
if err := unix.Connect(fd, sa); err != nil {
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed connect() to %08x.%08x", cid, port)
|
||||
}
|
||||
break
|
||||
}
|
||||
return newVsockConn(uintptr(fd), nil, &Addr{cid, port}), nil
|
||||
}
|
||||
|
||||
// Listen returns a net.Listener which can accept connections on the given port
|
||||
func Listen(cid, port uint32) (net.Listener, error) {
|
||||
fd, err := syscall.Socket(unix.AF_VSOCK, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sa := &unix.SockaddrVM{CID: cid, Port: port}
|
||||
if err = unix.Bind(fd, sa); err != nil {
|
||||
return nil, errors.Wrapf(err, "bind() to %08x.%08x failed", cid, port)
|
||||
}
|
||||
|
||||
err = syscall.Listen(fd, syscall.SOMAXCONN)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "listen() on %08x.%08x failed", cid, port)
|
||||
}
|
||||
return &vsockListener{fd, Addr{cid, port}}, nil
|
||||
}
|
||||
|
||||
type vsockListener struct {
|
||||
fd int
|
||||
local Addr
|
||||
}
|
||||
|
||||
// Accept accepts an incoming call and returns the new connection.
|
||||
func (v *vsockListener) Accept() (net.Conn, error) {
|
||||
fd, sa, err := unix.Accept(v.fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newVsockConn(uintptr(fd), &v.local, sockaddrToVsock(sa)), nil
|
||||
}
|
||||
|
||||
// Close closes the listening connection
|
||||
func (v *vsockListener) Close() error {
|
||||
// Note this won't cause the Accept to unblock.
|
||||
return unix.Close(v.fd)
|
||||
}
|
||||
|
||||
// Addr returns the address the Listener is listening on
|
||||
func (v *vsockListener) Addr() net.Addr {
|
||||
return v.local
|
||||
}
|
||||
|
||||
// a wrapper around FileConn which supports CloseRead and CloseWrite
|
||||
type vsockConn struct {
|
||||
vsock *os.File
|
||||
fd uintptr
|
||||
local *Addr
|
||||
remote *Addr
|
||||
}
|
||||
|
||||
func newVsockConn(fd uintptr, local, remote *Addr) *vsockConn {
|
||||
vsock := os.NewFile(fd, fmt.Sprintf("vsock:%d", fd))
|
||||
return &vsockConn{vsock: vsock, fd: fd, local: local, remote: remote}
|
||||
}
|
||||
|
||||
// LocalAddr returns the local address of a connection
|
||||
func (v *vsockConn) LocalAddr() net.Addr {
|
||||
return v.local
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address of a connection
|
||||
func (v *vsockConn) RemoteAddr() net.Addr {
|
||||
return v.remote
|
||||
}
|
||||
|
||||
// Close closes the connection
|
||||
func (v *vsockConn) Close() error {
|
||||
return v.vsock.Close()
|
||||
}
|
||||
|
||||
// CloseRead shuts down the reading side of a vsock connection
|
||||
func (v *vsockConn) CloseRead() error {
|
||||
return syscall.Shutdown(int(v.fd), syscall.SHUT_RD)
|
||||
}
|
||||
|
||||
// CloseWrite shuts down the writing side of a vsock connection
|
||||
func (v *vsockConn) CloseWrite() error {
|
||||
return syscall.Shutdown(int(v.fd), syscall.SHUT_WR)
|
||||
}
|
||||
|
||||
// Read reads data from the connection
|
||||
func (v *vsockConn) Read(buf []byte) (int, error) {
|
||||
return v.vsock.Read(buf)
|
||||
}
|
||||
|
||||
// Write writes data over the connection
|
||||
func (v *vsockConn) Write(buf []byte) (int, error) {
|
||||
return v.vsock.Write(buf)
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines associated with the connection
|
||||
func (v *vsockConn) SetDeadline(t time.Time) error {
|
||||
return nil // FIXME
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls.
|
||||
func (v *vsockConn) SetReadDeadline(t time.Time) error {
|
||||
return nil // FIXME
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for future Write calls
|
||||
func (v *vsockConn) SetWriteDeadline(t time.Time) error {
|
||||
return nil // FIXME
|
||||
}
|
||||
|
||||
// File duplicates the underlying socket descriptor and returns it.
|
||||
func (v *vsockConn) File() (*os.File, error) {
|
||||
// This is equivalent to dup(2) but creates the new fd with CLOEXEC already set.
|
||||
r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(v.vsock.Fd()), syscall.F_DUPFD_CLOEXEC, 0)
|
||||
if e1 != 0 {
|
||||
return nil, os.NewSyscallError("fcntl", e1)
|
||||
}
|
||||
return os.NewFile(r0, v.vsock.Name()), nil
|
||||
}
|
||||
2
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/vendor.conf
generated
vendored
Normal file
2
src/cmd/linuxkit/vendor/github.com/linuxkit/virtsock/vendor.conf
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/pkg/errors 2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb
|
||||
golang.org/x/sys 9c9d83fe39ed3fd2d9249fcf6b755891fff54b03
|
||||
191
src/cmd/linuxkit/vendor/github.com/moby/datakit/LICENSE.md
generated
vendored
191
src/cmd/linuxkit/vendor/github.com/moby/datakit/LICENSE.md
generated
vendored
@@ -1,191 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2013-2016 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
112
src/cmd/linuxkit/vendor/github.com/moby/datakit/README.md
generated
vendored
112
src/cmd/linuxkit/vendor/github.com/moby/datakit/README.md
generated
vendored
@@ -1,112 +0,0 @@
|
||||
## DataKit -- Orchestrate applications using a Git-like dataflow
|
||||
|
||||
*DataKit* is a tool to orchestrate applications using a Git-like dataflow. It
|
||||
revisits the UNIX pipeline concept, with a modern twist: streams of
|
||||
tree-structured data instead of raw text. DataKit allows you to define
|
||||
complex build pipelines over version-controlled data.
|
||||
|
||||
DataKit is currently used as the coordination
|
||||
layer for [HyperKit](http://github.com/docker/hyperkit), the
|
||||
hypervisor component of
|
||||
[Docker for Mac and Windows](https://blog.docker.com/2016/03/docker-for-mac-windows-beta/), and
|
||||
for the [DataKitCI][] continuous integration system.
|
||||
|
||||
---
|
||||
|
||||
[](https://travis-ci.org/moby/datakit)
|
||||
[](https://ci.appveyor.com/project/moby/datakit/branch/master)
|
||||
[](https://docker.github.io/datakit/)
|
||||
|
||||
There are several components in this repository:
|
||||
|
||||
- `src` contains the main DataKit service. This is a Git-like database to which other services can connect.
|
||||
- `ci` contains [DataKitCI][], a continuous integration system that uses DataKit to monitor repositories and store build results.
|
||||
- `ci/self-ci` is the CI configuration for DataKitCI that tests DataKit itself.
|
||||
- `bridge/github` is a service that monitors repositories on GitHub and syncs their metadata with a DataKit database.
|
||||
e.g. when a pull request is opened or updated, it will commit that information to DataKit. If you commit a status message to DataKit, the bridge will push it to GitHub.
|
||||
- `bridge/local` is a drop-in replacement for `bridge/github` that just monitors a local Git repository. This is useful for local testing.
|
||||
|
||||
### Quick Start
|
||||
|
||||
The easiest way to use DataKit is to start both the server and the client in containers.
|
||||
|
||||
To expose a Git repository as a 9p endpoint on port 5640 on a private network, run:
|
||||
|
||||
```shell
|
||||
$ docker network create datakit-net # create a private network
|
||||
$ docker run -it --net datakit-net --name datakit -v <path/to/git/repo>:/data datakit/db
|
||||
```
|
||||
|
||||
*Note*: The `--name datakit` option is mandatory. It will allow the client
|
||||
to connect to a known name on the private network.
|
||||
|
||||
You can then start a DataKit client, which will mount the 9p endpoint and
|
||||
expose the database as a filesystem API:
|
||||
|
||||
```shell
|
||||
# In an other terminal
|
||||
$ docker run -it --privileged --net datakit-net datakit/client
|
||||
$ ls /db
|
||||
branch remotes snapshots trees
|
||||
```
|
||||
|
||||
*Note*: the `--privileged` option is needed because the container will have
|
||||
to mount the 9p endpoint into its local filesystem.
|
||||
|
||||
Now you can explore, edit and script `/db`. See the
|
||||
[Filesystem API][]
|
||||
for more details.
|
||||
|
||||
### Building
|
||||
|
||||
The easiest way to build the DataKit project is to use [docker](https://docker.com),
|
||||
(which is what the
|
||||
[start-datakit.sh](https://github.com/moby/datakit/blob/master/scripts/start-datakit.sh) script
|
||||
does under the hood):
|
||||
|
||||
```shell
|
||||
docker build -t datakit/db -f Dockerfile .
|
||||
docker run -p 5640:5640 -it --rm datakit/db --listen-9p=tcp://0.0.0.0:5640
|
||||
```
|
||||
These commands will expose the database's 9p endpoint on port 5640.
|
||||
|
||||
If you want to build the project from source without Docker, you will need to install
|
||||
[ocaml](http://ocaml.org/) and [opam](http://opam.ocaml.org/). Then write:
|
||||
|
||||
```shell
|
||||
$ make depends
|
||||
$ make && make test
|
||||
```
|
||||
|
||||
For information about command-line options:
|
||||
|
||||
```shell
|
||||
$ datakit --help
|
||||
```
|
||||
|
||||
## Prometheus metric reporting
|
||||
|
||||
Run with `--listen-prometheus 9090` to expose metrics at `http://*:9090/metrics`.
|
||||
|
||||
Note: there is no encryption and no access control. You are expected to run the
|
||||
database in a container and to not export this port to the outside world. You
|
||||
can either collect the metrics by running a Prometheus service in a container
|
||||
on the same Docker network, or front the service with nginx or similar if you
|
||||
want to collect metrics remotely.
|
||||
|
||||
## Language bindings
|
||||
|
||||
* **Go** bindings are in the `api/go` directory.
|
||||
* **OCaml** bindings are in the `api/ocaml` directory. See `examples/ocaml-client` for an example.
|
||||
|
||||
## Licensing
|
||||
|
||||
DataKit is licensed under the Apache License, Version 2.0. See
|
||||
[LICENSE](https://github.com/moby/datakit/blob/master/LICENSE.md) for the full
|
||||
license text.
|
||||
|
||||
Contributions are welcome under the terms of this license. You may wish to browse
|
||||
the [weekly reports](reports) to read about overall activity in the repository.
|
||||
|
||||
[DataKitCI]: https://github.com/moby/datakit/tree/master/ci
|
||||
[Filesystem API]: https://github.com/moby/datakit/tree/master/9p.md
|
||||
1
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/README
generated
vendored
1
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/README
generated
vendored
@@ -1 +0,0 @@
|
||||
To run test on windows, launch the a datakit server with --url \\.\pipe\datakit-test
|
||||
352
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/client.go
generated
vendored
352
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/client.go
generated
vendored
@@ -1,352 +0,0 @@
|
||||
package datakit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
p9p "github.com/docker/go-p9p"
|
||||
"context"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
conn net.Conn
|
||||
session p9p.Session
|
||||
m *sync.Mutex
|
||||
c *sync.Cond
|
||||
usedFids map[p9p.Fid]bool
|
||||
freeFids []p9p.Fid
|
||||
root p9p.Fid
|
||||
}
|
||||
|
||||
var badFid = p9p.Fid(0)
|
||||
|
||||
var rwx = p9p.DMREAD | p9p.DMWRITE | p9p.DMEXEC
|
||||
var rx = p9p.DMREAD | p9p.DMEXEC
|
||||
var rw = p9p.DMREAD | p9p.DMWRITE
|
||||
var r = p9p.DMREAD
|
||||
var dirperm = uint32(rwx<<6 | rx<<3 | rx | p9p.DMDIR)
|
||||
var fileperm = uint32(rw<<6 | r<<3 | r)
|
||||
|
||||
// Dial opens a connection to a 9P server
|
||||
func Dial(ctx context.Context, network, address string) (*Client, error) {
|
||||
log.Println("Dialling", network, address)
|
||||
conn, err := net.Dial(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewClient(ctx, conn)
|
||||
}
|
||||
|
||||
// NewClient creates opens a connection with the p9p server
|
||||
func NewClient(ctx context.Context, conn net.Conn) (*Client, error) {
|
||||
session, err := p9p.NewSession(ctx, conn)
|
||||
if err != nil {
|
||||
log.Println("Failed to establish 9P session to", err)
|
||||
return nil, err
|
||||
}
|
||||
root := p9p.Fid(1)
|
||||
if _, err := session.Attach(ctx, root, p9p.NOFID, "anyone", "/"); err != nil {
|
||||
log.Println("Failed to Attach to filesystem", err)
|
||||
return nil, err
|
||||
}
|
||||
usedFids := make(map[p9p.Fid]bool, 0)
|
||||
freeFids := make([]p9p.Fid, 0)
|
||||
for i := 0; i < 128; i++ {
|
||||
fid := p9p.Fid(i)
|
||||
if fid == root {
|
||||
usedFids[fid] = true
|
||||
} else {
|
||||
freeFids = append(freeFids, fid)
|
||||
usedFids[fid] = false
|
||||
}
|
||||
}
|
||||
var m sync.Mutex
|
||||
c := sync.NewCond(&m)
|
||||
return &Client{conn, session, &m, c, usedFids, freeFids, root}, nil
|
||||
}
|
||||
|
||||
func (c *Client) Close(ctx context.Context) {
|
||||
if err := c.session.Clunk(ctx, c.root); err != nil {
|
||||
log.Println("Failed to Clunk root fid", err)
|
||||
} else {
|
||||
c.usedFids[c.root] = false
|
||||
}
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
for fid, inuse := range c.usedFids {
|
||||
if inuse {
|
||||
log.Println("I don't know how to flush: leaking", fid)
|
||||
}
|
||||
}
|
||||
c.conn.Close()
|
||||
}
|
||||
|
||||
// allocFid returns a fresh fid, bound to a clone of from
|
||||
func (c *Client) allocFid(ctx context.Context, from p9p.Fid) (p9p.Fid, error) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
for len(c.freeFids) == 0 {
|
||||
c.c.Wait()
|
||||
}
|
||||
fid := c.freeFids[len(c.freeFids)-1]
|
||||
c.freeFids = c.freeFids[0 : len(c.freeFids)-1]
|
||||
c.usedFids[fid] = true
|
||||
_, err := c.session.Walk(ctx, from, fid)
|
||||
if err != nil {
|
||||
log.Println("Failed to clone root fid", err)
|
||||
return badFid, err
|
||||
}
|
||||
return fid, nil
|
||||
}
|
||||
|
||||
// freeFid removes resources associated with the given fid
|
||||
func (c *Client) freeFid(ctx context.Context, fid p9p.Fid) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.freeFids = append(c.freeFids, fid)
|
||||
c.usedFids[fid] = false
|
||||
if err := c.session.Clunk(ctx, fid); err != nil {
|
||||
log.Println("Failed to clunk fid", fid)
|
||||
}
|
||||
c.c.Signal()
|
||||
}
|
||||
|
||||
// Mkdir acts like 'mkdir -p'
|
||||
func (c *Client) Mkdir(ctx context.Context, path ...string) error {
|
||||
fid, err := c.allocFid(ctx, c.root)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer c.freeFid(ctx, fid)
|
||||
// mkdir -p
|
||||
for _, dir := range path {
|
||||
dirfid, err := c.allocFid(ctx, fid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// dir may or may not exist
|
||||
_, _, _ = c.session.Create(ctx, dirfid, dir, dirperm, p9p.OREAD)
|
||||
c.freeFid(ctx, dirfid)
|
||||
// dir should definitely exist
|
||||
if _, err := c.session.Walk(ctx, fid, fid, dir); err != nil {
|
||||
log.Println("Failed to Walk to", dir, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var enoent = p9p.MessageRerror{Ename: "No such file or directory"}
|
||||
var enotdir = p9p.MessageRerror{Ename: "Can't walk from a file"}
|
||||
|
||||
// Remove acts like 'rm -f'
|
||||
func (c *Client) Remove(ctx context.Context, path ...string) error {
|
||||
fid, err := c.allocFid(ctx, c.root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.session.Walk(ctx, fid, fid, path...); err != nil {
|
||||
if err == enoent || err == enotdir {
|
||||
c.freeFid(ctx, fid)
|
||||
return nil
|
||||
}
|
||||
log.Println("Failed to walk to", path, err)
|
||||
c.freeFid(ctx, fid)
|
||||
return err
|
||||
}
|
||||
// Remove will cluck the fid, even if it fails
|
||||
if err := c.session.Remove(ctx, fid); err != nil {
|
||||
if err == enoent {
|
||||
return nil
|
||||
}
|
||||
log.Println("Failed to Remove", path, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type File struct {
|
||||
fid p9p.Fid
|
||||
c *Client
|
||||
m *sync.Mutex
|
||||
open bool
|
||||
}
|
||||
|
||||
// Create creates a file
|
||||
func (c *Client) Create(ctx context.Context, path ...string) (*File, error) {
|
||||
fid, err := c.allocFid(ctx, c.root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dir := path[0 : len(path)-1]
|
||||
_, err = c.session.Walk(ctx, fid, fid, dir...)
|
||||
if err != nil {
|
||||
if err != enoent {
|
||||
// This is a common error
|
||||
log.Println("Failed to Walk to", path, err)
|
||||
}
|
||||
c.freeFid(ctx, fid)
|
||||
return nil, err
|
||||
}
|
||||
_, _, err = c.session.Create(ctx, fid, path[len(path)-1], fileperm, p9p.ORDWR)
|
||||
if err != nil {
|
||||
log.Println("Failed to Create", path, err)
|
||||
return nil, err
|
||||
}
|
||||
var m sync.Mutex
|
||||
return &File{fid: fid, c: c, m: &m, open: true}, nil
|
||||
}
|
||||
|
||||
// Open opens a file
|
||||
func (c *Client) Open(ctx context.Context, mode p9p.Flag, path ...string) (*File, error) {
|
||||
fid, err := c.allocFid(ctx, c.root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = c.session.Walk(ctx, fid, fid, path...)
|
||||
if err != nil {
|
||||
if err != enoent {
|
||||
// This is a common error
|
||||
log.Println("Failed to Walk to", path, err)
|
||||
}
|
||||
c.freeFid(ctx, fid)
|
||||
return nil, err
|
||||
}
|
||||
_, _, err = c.session.Open(ctx, fid, mode)
|
||||
if err != nil {
|
||||
log.Println("Failed to Open", path, err)
|
||||
c.freeFid(ctx, fid)
|
||||
return nil, err
|
||||
}
|
||||
var m sync.Mutex
|
||||
return &File{fid: fid, c: c, m: &m, open: true}, nil
|
||||
}
|
||||
|
||||
// List a directory
|
||||
func (c *Client) List(ctx context.Context, path []string) ([]string, error) {
|
||||
file, err := c.Open(ctx, p9p.OREAD, path...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close(ctx)
|
||||
|
||||
msize, _ := c.session.Version()
|
||||
iounit := uint32(msize - 24) // size of message max minus fcall io header (Rread)
|
||||
|
||||
p := make([]byte, iounit)
|
||||
|
||||
n, err := c.session.Read(ctx, file.fid, p, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
files := []string{}
|
||||
|
||||
rd := bytes.NewReader(p[:n])
|
||||
codec := p9p.NewCodec() // TODO(stevvooe): Need way to resolve codec based on session.
|
||||
for {
|
||||
var d p9p.Dir
|
||||
if err := p9p.DecodeDir(codec, rd, &d); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return files, err
|
||||
}
|
||||
files = append(files, d.Name)
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// Close closes a file
|
||||
func (f *File) Close(ctx context.Context) {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
if f.open {
|
||||
f.c.freeFid(ctx, f.fid)
|
||||
}
|
||||
f.open = false
|
||||
}
|
||||
|
||||
// Read reads a value
|
||||
func (f *File) Read(ctx context.Context, p []byte, offset int64) (int, error) {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
if !f.open {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return f.c.session.Read(ctx, f.fid, p, offset)
|
||||
}
|
||||
|
||||
// Write writes a value
|
||||
func (f *File) Write(ctx context.Context, p []byte, offset int64) (int, error) {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
if !f.open {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return f.c.session.Write(ctx, f.fid, p, offset)
|
||||
}
|
||||
|
||||
type FileReader struct {
|
||||
file *File
|
||||
offset int64
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (f *File) NewFileReader(ctx context.Context) *FileReader {
|
||||
offset := int64(0)
|
||||
return &FileReader{file: f, offset: offset, ctx: ctx}
|
||||
}
|
||||
|
||||
func (f *FileReader) Read(p []byte) (int, error) {
|
||||
n, err := f.file.Read(f.ctx, p, f.offset)
|
||||
f.offset = f.offset + int64(n)
|
||||
if n == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
type ioFileReaderWriter struct {
|
||||
f *File
|
||||
ctx context.Context
|
||||
offset int64
|
||||
}
|
||||
|
||||
// NewIOReader creates a standard io.Reader at a given position in the file
|
||||
func (f *File) NewIOReader(ctx context.Context, offset int64) io.Reader {
|
||||
return &ioFileReaderWriter{f, ctx, offset}
|
||||
}
|
||||
|
||||
// NewIOWriter creates a standard io.Writer at a given position in the file
|
||||
func (f *File) NewIOWriter(ctx context.Context, offset int64) io.Writer {
|
||||
return &ioFileReaderWriter{f, ctx, offset}
|
||||
}
|
||||
|
||||
func (r *ioFileReaderWriter) Read(p []byte) (n int, err error) {
|
||||
|
||||
r.f.m.Lock()
|
||||
defer r.f.m.Unlock()
|
||||
n, err = r.f.c.session.Read(r.ctx, r.f.fid, p, r.offset)
|
||||
|
||||
r.offset += int64(n)
|
||||
return n, err
|
||||
}
|
||||
func (w *ioFileReaderWriter) Write(p []byte) (n int, err error) {
|
||||
w.f.m.Lock()
|
||||
defer w.f.m.Unlock()
|
||||
for err == nil || err == io.ErrShortWrite {
|
||||
var written int
|
||||
written, err = w.f.c.session.Write(w.ctx, w.f.fid, p, w.offset)
|
||||
p = p[written:]
|
||||
w.offset += int64(written)
|
||||
n += written
|
||||
if len(p) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
380
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/config.go
generated
vendored
380
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/config.go
generated
vendored
@@ -1,380 +0,0 @@
|
||||
package datakit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"context"
|
||||
)
|
||||
|
||||
type Version int
|
||||
|
||||
var InitialVersion = Version(0)
|
||||
|
||||
// Record is a typed view on top of a database branch
|
||||
type Record struct {
|
||||
client *Client
|
||||
path []string // directory inside the store
|
||||
version Version
|
||||
schemaF *IntField
|
||||
fields []*StringRefField // registered fields, for schema upgrades
|
||||
lookupB []string // priority ordered list of branches to look up values in
|
||||
defaultsB string // name of the branch containing built-in defaults
|
||||
stateB string // name of the branch containing run-time state
|
||||
event chan (interface{})
|
||||
onUpdate [](func([]*Snapshot, Version))
|
||||
}
|
||||
|
||||
func NewRecord(ctx context.Context, client *Client, lookupB []string, defaultsB string, stateB string, path []string) (*Record, error) {
|
||||
event := make(chan (interface{}), 0)
|
||||
for _, b := range append(lookupB, stateB) {
|
||||
// Create the branch if it doesn't exist
|
||||
t, err := NewTransaction(ctx, client, b)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open a new transaction: %#v", err)
|
||||
}
|
||||
if err = t.Write(ctx, []string{"branch-created"}, ""); err != nil {
|
||||
log.Fatalf("Failed to write branch-created: %#v", err)
|
||||
}
|
||||
if err = t.Commit(ctx, "Creating branch"); err != nil {
|
||||
log.Fatalf("Failed to commit transaction: %#v", err)
|
||||
}
|
||||
}
|
||||
for _, b := range lookupB {
|
||||
if err := client.Mkdir(ctx, "branch", b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w, err := NewWatch(ctx, client, b, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
_, err := w.Next(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("Snapshot has changed\n")
|
||||
event <- 0
|
||||
}
|
||||
}()
|
||||
}
|
||||
onUpdate := make([](func([]*Snapshot, Version)), 0)
|
||||
fields := make([]*StringRefField, 0)
|
||||
r := &Record{
|
||||
client: client,
|
||||
path: path,
|
||||
version: InitialVersion,
|
||||
fields: fields,
|
||||
lookupB: lookupB,
|
||||
defaultsB: defaultsB,
|
||||
stateB: stateB,
|
||||
event: event,
|
||||
onUpdate: onUpdate,
|
||||
}
|
||||
r.schemaF = r.IntField("schema-version", 1)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *Record) updateAll(ctx context.Context) error {
|
||||
snapshots := make([]*Snapshot, 0)
|
||||
for _, b := range r.lookupB {
|
||||
head, err := Head(ctx, r.client, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
snap := NewSnapshot(ctx, r.client, COMMIT, head)
|
||||
snapshots = append(snapshots, snap)
|
||||
}
|
||||
for _, fn := range r.onUpdate {
|
||||
fn(snapshots, r.version)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Record) Seal(ctx context.Context) error {
|
||||
return r.updateAll(ctx)
|
||||
}
|
||||
|
||||
func (r *Record) Wait(ctx context.Context) error {
|
||||
<-r.event
|
||||
r.version = r.version + 1
|
||||
return r.updateAll(ctx)
|
||||
}
|
||||
|
||||
func (r *Record) Upgrade(ctx context.Context, schemaVersion int) error {
|
||||
currentVersion, _ := r.schemaF.Get()
|
||||
if schemaVersion <= currentVersion {
|
||||
log.Printf("No schema upgrade necessary because new version (%d) <= current version (%d)\n", schemaVersion, currentVersion)
|
||||
return nil
|
||||
}
|
||||
r.schemaF.defaultInt = schemaVersion
|
||||
defaultString := fmt.Sprintf("%d", schemaVersion)
|
||||
r.schemaF.raw.defaultValue = &defaultString
|
||||
// Create defaults branch
|
||||
log.Printf("Performing schema upgrade to version %d\n", schemaVersion)
|
||||
t, err := NewTransaction(ctx, r.client, r.defaultsB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// For each known field, write default value to branch
|
||||
for _, f := range r.fields {
|
||||
p := append(r.path, f.path...)
|
||||
if f.defaultValue == nil {
|
||||
err = t.Remove(ctx, p)
|
||||
} else {
|
||||
err = t.Write(ctx, p, *f.defaultValue)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Merge to the defaults branch
|
||||
err = t.Commit(ctx, fmt.Sprintf("Upgrade to schema version %d", schemaVersion))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.Wait(ctx)
|
||||
}
|
||||
|
||||
// fillInDefault updates the default branch to contain the new value.
|
||||
func (r *Record) fillInDefault(path []string, valueref *string) error {
|
||||
ctx := context.Background()
|
||||
t, err := NewTransaction(ctx, r.client, r.defaultsB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p := append(r.path, path...)
|
||||
if valueref == nil {
|
||||
log.Printf("Removing default value at %s", strings.Join(p, "/"))
|
||||
|
||||
if err = t.Remove(ctx, p); err != nil {
|
||||
log.Printf("Failed to remove key at %s", strings.Join(p, "/"))
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Printf("Updating default value at %s to %s", strings.Join(p, "/"), *valueref)
|
||||
if err = t.Write(ctx, p, *valueref); err != nil {
|
||||
log.Printf("Failed to write key %s = %s", strings.Join(p, "/"), *valueref)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return t.Commit(ctx, fmt.Sprintf("fill-in default for %s", p))
|
||||
}
|
||||
|
||||
func (r *Record) SetMultiple(description string, fields []*StringField, values []string) error {
|
||||
if len(fields) != len(values) {
|
||||
return fmt.Errorf("Length of fields and values is not equal")
|
||||
}
|
||||
ctx := context.Background()
|
||||
t, err := NewTransaction(ctx, r.client, r.lookupB[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, k := range fields {
|
||||
p := append(r.path, k.raw.path...)
|
||||
v := values[i]
|
||||
log.Printf("Setting value in store: %#v=%s\n", p, v)
|
||||
err = t.Write(ctx, p, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return t.Commit(ctx, description)
|
||||
}
|
||||
|
||||
type StringRefField struct {
|
||||
path []string
|
||||
value *string
|
||||
defaultValue *string
|
||||
version Version // version of last change
|
||||
record *Record
|
||||
}
|
||||
|
||||
// Set unconditionally sets the value of the key
|
||||
func (f *StringRefField) Set(description string, value *string) error {
|
||||
// TODO: maybe this should return Version, too?
|
||||
ctx := context.Background()
|
||||
p := append(f.record.path, f.path...)
|
||||
log.Printf("Setting value in store: %#v=%#v\n", p, value)
|
||||
t, err := NewTransaction(ctx, f.record.client, f.record.lookupB[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value == nil {
|
||||
err = t.Remove(ctx, p)
|
||||
} else {
|
||||
err = t.Write(ctx, p, *value)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.Commit(ctx, fmt.Sprintf("Unconditionally set %s: %s", f.path, description))
|
||||
}
|
||||
|
||||
// Get retrieves the current value of the key
|
||||
func (f *StringRefField) Get() (*string, Version) {
|
||||
if f.value == nil {
|
||||
return nil, f.version
|
||||
}
|
||||
raw := strings.TrimSpace(*f.value)
|
||||
return &raw, f.version
|
||||
}
|
||||
|
||||
// HasChanged returns true if the key has changed since the given version
|
||||
func (f *StringRefField) HasChanged(version Version) bool {
|
||||
return version < f.version
|
||||
}
|
||||
|
||||
// StringRefField defines a string option which can be nil with a specified
|
||||
// key and default value
|
||||
func (f *Record) StringRefField(key string, value *string) *StringRefField {
|
||||
path := strings.Split(key, "/")
|
||||
field := &StringRefField{path: path, value: value, defaultValue: value, version: InitialVersion, record: f}
|
||||
// If the value is not in the database, write the default Value.
|
||||
err := f.fillInDefault(path, value)
|
||||
if err != nil {
|
||||
log.Println("Failed to write default value", key, "=", value)
|
||||
}
|
||||
fn := func(snaps []*Snapshot, version Version) {
|
||||
ctx := context.Background()
|
||||
var newValue *string
|
||||
for _, snap := range snaps {
|
||||
v, err := snap.Read(ctx, append(f.path, path...))
|
||||
if err != nil {
|
||||
if err != enoent {
|
||||
log.Println("Failed to read key", key, "from directory snapshot", snap)
|
||||
return
|
||||
}
|
||||
// if enoent then newValue == nil
|
||||
} else {
|
||||
newValue = &v
|
||||
break
|
||||
}
|
||||
}
|
||||
if (field.value == nil && newValue != nil) || (field.value != nil && newValue == nil) || (field.value != nil && newValue != nil && *field.value != *newValue) {
|
||||
field.value = newValue
|
||||
field.version = version
|
||||
}
|
||||
|
||||
// Update the value in memory and in the state branch
|
||||
t, err := NewTransaction(ctx, f.client, f.stateB)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create transaction for updating state branch: %#v", err)
|
||||
}
|
||||
if newValue != nil {
|
||||
if err = t.Write(ctx, append(f.path, path...), *newValue); err != nil {
|
||||
log.Fatalf("Failed to write state %#v = %s: %#v", path, *newValue, err)
|
||||
}
|
||||
} else {
|
||||
if err = t.Remove(ctx, append(f.path, path...)); err != nil {
|
||||
log.Fatalf("Failed to remove state %#v: %#v", path, err)
|
||||
}
|
||||
}
|
||||
if err = t.Commit(ctx, "Updating state branch"); err != nil {
|
||||
log.Fatalf("Failed to commit transaction: %#v", err)
|
||||
}
|
||||
|
||||
}
|
||||
f.onUpdate = append(f.onUpdate, fn)
|
||||
//fn(f.version)
|
||||
f.fields = append(f.fields, field)
|
||||
return field
|
||||
}
|
||||
|
||||
type StringField struct {
|
||||
raw *StringRefField
|
||||
defaultString string
|
||||
}
|
||||
|
||||
// Get retrieves the current value of the key
|
||||
func (f *StringField) Get() (string, Version) {
|
||||
if f.raw.value == nil {
|
||||
log.Printf("Failed to find string in database at %s, defaulting to %s", strings.Join(f.raw.path, "/"), f.defaultString)
|
||||
return f.defaultString, f.raw.version
|
||||
}
|
||||
return *f.raw.value, f.raw.version
|
||||
}
|
||||
|
||||
// Set unconditionally sets the value of the key
|
||||
func (f *StringField) Set(description string, value string) error {
|
||||
return f.raw.Set(description, &value)
|
||||
}
|
||||
|
||||
// HasChanged returns true if the key has changed since the given version
|
||||
func (f *StringField) HasChanged(version Version) bool {
|
||||
return version < f.raw.version
|
||||
}
|
||||
|
||||
// StringField defines a string
|
||||
func (f *Record) StringField(key string, value string) *StringField {
|
||||
raw := f.StringRefField(key, &value)
|
||||
return &StringField{raw: raw, defaultString: value}
|
||||
}
|
||||
|
||||
type IntField struct {
|
||||
raw *StringRefField
|
||||
defaultInt int
|
||||
}
|
||||
|
||||
// Get retrieves the current value of the key
|
||||
func (f *IntField) Get() (int, Version) {
|
||||
if f.raw.value == nil {
|
||||
log.Printf("Key %s missing in database, defaulting value to %t", strings.Join(f.raw.path, "/"), f.defaultInt)
|
||||
return f.defaultInt, f.raw.version
|
||||
}
|
||||
value64, err := strconv.ParseInt(strings.TrimSpace(*f.raw.value), 10, 0)
|
||||
if err != nil {
|
||||
// revert to default if we can't parse the result
|
||||
log.Printf("Failed to parse int in database: '%s', defaulting to %d", f.raw.value, f.defaultInt)
|
||||
return f.defaultInt, f.raw.version
|
||||
}
|
||||
return int(value64), f.raw.version
|
||||
}
|
||||
|
||||
// HasChanged returns true if the key has changed since the given version
|
||||
func (f *IntField) HasChanged(version Version) bool {
|
||||
return version < f.raw.version
|
||||
}
|
||||
|
||||
// IntField defines an boolean option with a specified key and default value
|
||||
func (f *Record) IntField(key string, value int) *IntField {
|
||||
stringValue := fmt.Sprintf("%d", value)
|
||||
raw := f.StringRefField(key, &stringValue)
|
||||
return &IntField{raw: raw, defaultInt: value}
|
||||
}
|
||||
|
||||
type BoolField struct {
|
||||
raw *StringRefField
|
||||
defaultBool bool
|
||||
}
|
||||
|
||||
// Get retrieves the current value of the key
|
||||
func (f *BoolField) Get() (bool, Version) {
|
||||
if f.raw.value == nil {
|
||||
log.Printf("Key %s missing in database, defaulting value to %t", strings.Join(f.raw.path, "/"), f.defaultBool)
|
||||
return f.defaultBool, f.raw.version
|
||||
}
|
||||
value, err := strconv.ParseBool(strings.TrimSpace(*f.raw.value))
|
||||
if err != nil {
|
||||
// revert to default if we can't parse the result
|
||||
log.Printf("Failed to parse boolean in database: '%s', defaulting to %t", f.raw.value, f.defaultBool)
|
||||
return f.defaultBool, f.raw.version
|
||||
}
|
||||
return value, f.raw.version
|
||||
}
|
||||
|
||||
// HasChanged returns true if the key has changed since the given version
|
||||
func (f *BoolField) HasChanged(version Version) bool {
|
||||
return version < f.raw.version
|
||||
}
|
||||
|
||||
// BoolField defines an boolean option with a specified key and default value
|
||||
func (f *Record) BoolField(key string, value bool) *BoolField {
|
||||
stringValue := fmt.Sprintf("%t", value)
|
||||
raw := f.StringRefField(key, &stringValue)
|
||||
return &BoolField{raw: raw, defaultBool: value}
|
||||
}
|
||||
5
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/doc.go
generated
vendored
5
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/doc.go
generated
vendored
@@ -1,5 +0,0 @@
|
||||
/*
|
||||
The datakit package contains common patterns over 9P, which avoids the need
|
||||
for applications to use 9P directly.
|
||||
*/
|
||||
package datakit
|
||||
87
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/snapshot.go
generated
vendored
87
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/snapshot.go
generated
vendored
@@ -1,87 +0,0 @@
|
||||
package datakit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
p9p "github.com/docker/go-p9p"
|
||||
"context"
|
||||
)
|
||||
|
||||
type SnapshotKind uint8
|
||||
|
||||
const (
|
||||
COMMIT SnapshotKind = 0x01 // from a commit hash
|
||||
OBJECT SnapshotKind = 0x02 // from an object hash
|
||||
)
|
||||
|
||||
type snapshot struct {
|
||||
client *Client
|
||||
kind SnapshotKind
|
||||
thing string
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
snapshot
|
||||
}
|
||||
|
||||
// NewSnapshot opens a new snapshot referencing the given object.
|
||||
func NewSnapshot(ctx context.Context, client *Client, kind SnapshotKind, thing string) *Snapshot {
|
||||
return &Snapshot{snapshot{client: client, kind: kind, thing: thing}}
|
||||
}
|
||||
|
||||
// Head retrieves the commit sha of the given branch
|
||||
func Head(ctx context.Context, client *Client, fromBranch string) (string, error) {
|
||||
// SHA=$(cat branch/<fromBranch>/head)
|
||||
file, err := client.Open(ctx, p9p.ORDWR, "branch", fromBranch, "head")
|
||||
if err != nil {
|
||||
log.Println("Failed to open branch/", fromBranch, "/head")
|
||||
return "", err
|
||||
}
|
||||
defer file.Close(ctx)
|
||||
buf := make([]byte, 512)
|
||||
n, err := file.Read(ctx, buf, 0)
|
||||
if err != nil {
|
||||
log.Println("Failed to Read branch", fromBranch, "head", err)
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(buf[0:n])), nil
|
||||
}
|
||||
|
||||
func (s *Snapshot) getFullPath(path []string) []string {
|
||||
var p []string
|
||||
|
||||
switch s.kind {
|
||||
case COMMIT:
|
||||
p = []string{"snapshots", s.thing, "ro"}
|
||||
case OBJECT:
|
||||
p = []string{"trees", s.thing}
|
||||
}
|
||||
|
||||
for _, element := range path {
|
||||
p = append(p, element)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Read reads a value from the snapshot
|
||||
func (s *Snapshot) Read(ctx context.Context, path []string) (string, error) {
|
||||
p := s.getFullPath(path)
|
||||
file, err := s.client.Open(ctx, p9p.OREAD, p...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close(ctx)
|
||||
reader := file.NewIOReader(ctx, 0)
|
||||
buf := bytes.NewBuffer(nil)
|
||||
io.Copy(buf, reader)
|
||||
return string(buf.Bytes()), nil
|
||||
}
|
||||
|
||||
// List returns filenames list in directory
|
||||
func (s *Snapshot) List(ctx context.Context, path []string) ([]string, error) {
|
||||
p := s.getFullPath(path)
|
||||
return s.client.List(ctx, p)
|
||||
}
|
||||
136
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/transaction.go
generated
vendored
136
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/transaction.go
generated
vendored
@@ -1,136 +0,0 @@
|
||||
package datakit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
|
||||
p9p "github.com/docker/go-p9p"
|
||||
"context"
|
||||
)
|
||||
|
||||
type transaction struct {
|
||||
client *Client
|
||||
fromBranch string
|
||||
newBranch string
|
||||
}
|
||||
|
||||
var nextTransaction = int64(0)
|
||||
|
||||
// NewTransaction opens a new transaction originating from fromBranch, named
|
||||
// newBranch.
|
||||
func NewTransaction(ctx context.Context, client *Client, fromBranch string) (*transaction, error) {
|
||||
|
||||
id := atomic.AddInt64(&nextTransaction, 1)
|
||||
newBranch := strconv.FormatInt(id, 10)
|
||||
err := client.Mkdir(ctx, "branch", fromBranch)
|
||||
if err != nil {
|
||||
log.Println("Failed to Create branch/", fromBranch, err)
|
||||
return nil, err
|
||||
}
|
||||
err = client.Mkdir(ctx, "branch", fromBranch, "transactions", newBranch)
|
||||
if err != nil {
|
||||
log.Println("Failed to Create branch/", fromBranch, "/transactions/", newBranch, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &transaction{client: client, fromBranch: fromBranch, newBranch: newBranch}, nil
|
||||
}
|
||||
|
||||
func (t *transaction) close(ctx context.Context) {
|
||||
// TODO: do we need to clear up unmerged branches?
|
||||
}
|
||||
|
||||
// Abort ensures the update will not be committed.
|
||||
func (t *transaction) Abort(ctx context.Context) {
|
||||
t.close(ctx)
|
||||
}
|
||||
|
||||
// Commit merges the newBranch back into the fromBranch, or fails
|
||||
func (t *transaction) Commit(ctx context.Context, msg string) error {
|
||||
// msg
|
||||
msgPath := []string{"branch", t.fromBranch, "transactions", t.newBranch, "msg"}
|
||||
msgFile, err := t.client.Open(ctx, p9p.ORDWR, msgPath...)
|
||||
if err != nil {
|
||||
log.Println("Failed to Open msg", err)
|
||||
return err
|
||||
}
|
||||
defer msgFile.Close(ctx)
|
||||
_, err = msgFile.Write(ctx, []byte(msg), 0)
|
||||
if err != nil {
|
||||
log.Println("Failed to Write msg", err)
|
||||
}
|
||||
|
||||
// ctl
|
||||
ctlPath := []string{"branch", t.fromBranch, "transactions", t.newBranch, "ctl"}
|
||||
ctlFile, err := t.client.Open(ctx, p9p.ORDWR, ctlPath...)
|
||||
if err != nil {
|
||||
log.Println("Failed to Open ctl", err)
|
||||
return err
|
||||
}
|
||||
defer ctlFile.Close(ctx)
|
||||
_, err = ctlFile.Write(ctx, []byte("commit"), 0)
|
||||
if err != nil {
|
||||
log.Println("Failed to Write ctl", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write updates a key=value pair within the transaction.
|
||||
func (t *transaction) Write(ctx context.Context, path []string, value string) error {
|
||||
p := []string{"branch", t.fromBranch, "transactions", t.newBranch, "rw"}
|
||||
for _, dir := range path[0 : len(path)-1] {
|
||||
p = append(p, dir)
|
||||
}
|
||||
err := t.client.Mkdir(ctx, p...)
|
||||
if err != nil {
|
||||
log.Println("Failed to Mkdir", p)
|
||||
}
|
||||
p = append(p, path[len(path)-1])
|
||||
file, err := t.client.Create(ctx, p...)
|
||||
if err != nil {
|
||||
log.Println("Failed to Create", p)
|
||||
return err
|
||||
}
|
||||
defer file.Close(ctx)
|
||||
writer := file.NewIOWriter(ctx, 0)
|
||||
_, err = writer.Write([]byte(value))
|
||||
if err != nil {
|
||||
log.Println("Failed to Write", path, "=", value, ":", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read reads a key within the transaction.
|
||||
func (t *transaction) Read(ctx context.Context, path []string) (string, error) {
|
||||
p := []string{"branch", t.fromBranch, "transactions", t.newBranch, "rw"}
|
||||
for _, dir := range path[0 : len(path)-1] {
|
||||
p = append(p, dir)
|
||||
}
|
||||
file, err := t.client.Open(ctx, p9p.OREAD, p...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close(ctx)
|
||||
reader := file.NewIOReader(ctx, 0)
|
||||
buf := bytes.NewBuffer(nil)
|
||||
io.Copy(buf, reader)
|
||||
return string(buf.Bytes()), nil
|
||||
}
|
||||
|
||||
// Remove deletes a key within the transaction.
|
||||
func (t *transaction) Remove(ctx context.Context, path []string) error {
|
||||
p := []string{"branch", t.fromBranch, "transactions", t.newBranch, "rw"}
|
||||
for _, dir := range path {
|
||||
p = append(p, dir)
|
||||
}
|
||||
err := t.client.Remove(ctx, p...)
|
||||
if err != nil {
|
||||
log.Println("Failed to Remove ", p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
77
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/watch.go
generated
vendored
77
src/cmd/linuxkit/vendor/github.com/moby/datakit/api/go-datakit/watch.go
generated
vendored
@@ -1,77 +0,0 @@
|
||||
package datakit
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
p9p "github.com/docker/go-p9p"
|
||||
"context"
|
||||
)
|
||||
|
||||
type watch struct {
|
||||
client *Client
|
||||
file *File
|
||||
offset int64 // current offset within head.live file
|
||||
}
|
||||
|
||||
type Watch struct {
|
||||
watch
|
||||
}
|
||||
|
||||
// NewWatch starts watching a path within a branch
|
||||
func NewWatch(ctx context.Context, client *Client, fromBranch string, path []string) (*Watch, error) {
|
||||
// SHA=$(cat branch/<fromBranch>/watch/<path.node>/tree.live)
|
||||
p := []string{"branch", fromBranch, "watch"}
|
||||
for _, dir := range path {
|
||||
p = append(p, dir+".node")
|
||||
}
|
||||
p = append(p, "tree.live")
|
||||
file, err := client.Open(ctx, p9p.OREAD, p...)
|
||||
if err != nil {
|
||||
log.Println("Failed to open", p, err)
|
||||
return nil, err
|
||||
}
|
||||
offset := int64(0)
|
||||
return &Watch{watch{client: client, file: file, offset: offset}}, nil
|
||||
}
|
||||
|
||||
func (w *Watch) Next(ctx context.Context) (*Snapshot, error) {
|
||||
buf := make([]byte, 512)
|
||||
sawFlush := false
|
||||
for {
|
||||
// NOTE: irmin9p-direct will never return a fragment;
|
||||
// we can rely on the buffer containing a whold number
|
||||
// of lines.
|
||||
n, err := w.file.Read(ctx, buf, w.offset)
|
||||
if n == 0 {
|
||||
// Two reads of "" in a row means end-of-file
|
||||
if sawFlush {
|
||||
return nil, io.EOF
|
||||
} else {
|
||||
sawFlush = true
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
sawFlush = false
|
||||
}
|
||||
w.offset = w.offset + int64(n)
|
||||
if err != nil {
|
||||
log.Println("Failed to Read head.live", err)
|
||||
return nil, io.EOF
|
||||
}
|
||||
lines := strings.Split(string(buf[0:n]), "\n")
|
||||
// Use the last non-empty line
|
||||
thing := ""
|
||||
for _, line := range lines {
|
||||
if line != "" {
|
||||
thing = line
|
||||
}
|
||||
}
|
||||
return NewSnapshot(ctx, w.client, OBJECT, thing), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watch) Close(ctx context.Context) {
|
||||
w.file.Close(ctx)
|
||||
}
|
||||
39
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/README.md
generated
vendored
39
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/README.md
generated
vendored
@@ -14,21 +14,42 @@ VPNKit is a set of tools and services for helping [HyperKit](https://github.com/
|
||||
VMs interoperate with host VPN configurations.
|
||||
|
||||
|
||||
Building on Unix
|
||||
----------------
|
||||
Building on Unix (including Mac)
|
||||
--------------------------------
|
||||
|
||||
First install `wget`, `opam` using your package manager of choice.
|
||||
|
||||
Build all the dependencies and the program itself with:
|
||||
First install `wget`, `opam` and `pkg-config` using your package manager of choice.
|
||||
|
||||
If you are an existing `opam` user then you can either build against your existing `opam`
|
||||
package universe, or the custom universe contained in this repo. To use the custom universe,
|
||||
ensure that you unset your `OPAMROOT` environment variable:
|
||||
```
|
||||
cd [path to vpnkit source]
|
||||
opam remote add vpnkit ./repo/darwin
|
||||
opam install --deps-only vpnkit
|
||||
unset OPAMROOT
|
||||
```
|
||||
|
||||
To build, type
|
||||
```
|
||||
make
|
||||
```
|
||||
The first build will take a little longer as it will build all the package dependencies first.
|
||||
|
||||
When the build succeeds the `vpnkit.exe` binary should be available in the current directory.
|
||||
|
||||
Building on Windows
|
||||
-------------------
|
||||
|
||||
First install the [OCaml environment with Cygwin](https://fdopen.github.io/opam-repository-mingw/installation/).
|
||||
Note that although the Cygwin tools are needed for the build scripts, Cygwin itself will not
|
||||
be linked to the final executable.
|
||||
|
||||
Inside the `OCaml64` (Cygwin) shell, unset the `OPAMROOT` environment and build by:
|
||||
```
|
||||
unset OPAMROOT
|
||||
make
|
||||
```
|
||||
|
||||
When the build succeeds the `vpnkit` binary should be available in the current path.
|
||||
The first build will take a little longer as it will build all the package dependencies first.
|
||||
|
||||
When the build succeeds the `vpnkit.exe` binary should be available in the current directory.
|
||||
|
||||
Running with hyperkit
|
||||
---------------------
|
||||
|
||||
154
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-9pmount-vsock/9pmount-vsock.c
generated
vendored
154
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-9pmount-vsock/9pmount-vsock.c
generated
vendored
@@ -2,7 +2,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -11,8 +10,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/vm_sockets.h>
|
||||
|
||||
#include "hvsock.h"
|
||||
#include "log.h"
|
||||
|
||||
#define NONE 0
|
||||
#define LISTEN 1
|
||||
@@ -20,15 +22,8 @@
|
||||
|
||||
int mode = NONE;
|
||||
|
||||
char *default_sid = "C378280D-DA14-42C8-A24E-0DE92A1028E2";
|
||||
char *mount = "/bin/mount";
|
||||
|
||||
void fatal(const char *msg)
|
||||
{
|
||||
syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int handle(int fd, char *tag, char *path)
|
||||
{
|
||||
char *options = NULL;
|
||||
@@ -57,14 +52,13 @@ static int handle(int fd, char *tag, char *path)
|
||||
|
||||
res = waitpid(pid, &status, 0);
|
||||
if (res == -1) {
|
||||
syslog(LOG_CRIT,
|
||||
"waitpid failed: %d. %s", errno, strerror(errno));
|
||||
ERROR("waitpid failed: %d. %s", errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
static int create_listening_socket(GUID serviceid)
|
||||
static int create_listening_hvsocket(GUID serviceid)
|
||||
{
|
||||
SOCKADDR_HV sa;
|
||||
int lsock;
|
||||
@@ -72,8 +66,9 @@ static int create_listening_socket(GUID serviceid)
|
||||
|
||||
lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (lsock == -1)
|
||||
fatal("socket()");
|
||||
return -1;
|
||||
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.Family = AF_HYPERV;
|
||||
sa.Reserved = 0;
|
||||
sa.VmId = HV_GUID_WILDCARD;
|
||||
@@ -81,16 +76,44 @@ static int create_listening_socket(GUID serviceid)
|
||||
|
||||
res = bind(lsock, (const struct sockaddr *)&sa, sizeof(sa));
|
||||
if (res == -1)
|
||||
fatal("bind()");
|
||||
return -1; /* ignore the fd leak */
|
||||
|
||||
res = listen(lsock, 1);
|
||||
if (res == -1)
|
||||
fatal("listen()");
|
||||
return -1; /* ignore the fd leak */
|
||||
|
||||
return lsock;
|
||||
}
|
||||
|
||||
static int connect_socket(GUID serviceid)
|
||||
static int create_listening_vsocket(long port)
|
||||
{
|
||||
struct sockaddr_vm sa;
|
||||
int lsock;
|
||||
int res;
|
||||
|
||||
lsock = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
if (lsock == -1)
|
||||
return -1;
|
||||
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.svm_family = AF_VSOCK;
|
||||
sa.svm_reserved1 = 0;
|
||||
sa.svm_port = port;
|
||||
sa.svm_cid = VMADDR_CID_ANY;
|
||||
|
||||
res = bind(lsock, (const struct sockaddr *)&sa, sizeof(sa));
|
||||
if (res == -1)
|
||||
return -1; /* ignore the fd leak */
|
||||
|
||||
res = listen(lsock, 1);
|
||||
if (res == -1)
|
||||
return -1; /* ignore the fd leak */
|
||||
|
||||
return lsock;
|
||||
}
|
||||
|
||||
|
||||
static int connect_hvsocket(GUID serviceid)
|
||||
{
|
||||
SOCKADDR_HV sa;
|
||||
int sock;
|
||||
@@ -98,8 +121,9 @@ static int connect_socket(GUID serviceid)
|
||||
|
||||
sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (sock == -1)
|
||||
fatal("socket()");
|
||||
return -1;
|
||||
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.Family = AF_HYPERV;
|
||||
sa.Reserved = 0;
|
||||
sa.VmId = HV_GUID_PARENT;
|
||||
@@ -107,12 +131,35 @@ static int connect_socket(GUID serviceid)
|
||||
|
||||
res = connect(sock, (const struct sockaddr *)&sa, sizeof(sa));
|
||||
if (res == -1)
|
||||
fatal("connect()");
|
||||
return -1; /* ignore the fd leak */
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static int accept_socket(int lsock)
|
||||
static int connect_vsocket(long port)
|
||||
{
|
||||
struct sockaddr_vm sa;
|
||||
int sock;
|
||||
int res;
|
||||
|
||||
sock = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
if (sock == -1)
|
||||
return -1;
|
||||
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.svm_family = AF_VSOCK;
|
||||
sa.svm_reserved1 = 0;
|
||||
sa.svm_port = port;
|
||||
sa.svm_cid = VMADDR_CID_HOST;
|
||||
|
||||
res = connect(sock, (const struct sockaddr *)&sa, sizeof(sa));
|
||||
if (res == -1)
|
||||
return -1; /* ignore the fd leak */
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static int accept_hvsocket(int lsock)
|
||||
{
|
||||
SOCKADDR_HV sac;
|
||||
socklen_t socklen = sizeof(sac);
|
||||
@@ -122,21 +169,35 @@ static int accept_socket(int lsock)
|
||||
if (csock == -1)
|
||||
fatal("accept()");
|
||||
|
||||
syslog(LOG_INFO, "Connect from: " GUID_FMT ":" GUID_FMT "\n",
|
||||
INFO("Connect from: " GUID_FMT ":" GUID_FMT "\n",
|
||||
GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId));
|
||||
|
||||
return csock;
|
||||
}
|
||||
|
||||
static int accept_vsocket(int lsock)
|
||||
{
|
||||
struct sockaddr_vm sac;
|
||||
socklen_t socklen = sizeof(sac);
|
||||
int csock;
|
||||
|
||||
csock = accept(lsock, (struct sockaddr *)&sac, &socklen);
|
||||
if (csock == -1)
|
||||
fatal("accept()");
|
||||
|
||||
INFO("Connect from: port=%x cid=%d", sac.svm_port, sac.svm_cid);
|
||||
|
||||
return csock;
|
||||
}
|
||||
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("%s: mount a 9P filesystem from an hvsock connection\n", name);
|
||||
printf("usage:\n");
|
||||
printf("\t[--serviceid <guid>] <listen | connect> <tag> <path>\n");
|
||||
printf("\t[--vsock port] <listen | connect> <tag> <path>\n");
|
||||
printf("where\n");
|
||||
printf("\t--serviceid <guid>: use <guid> as the well-known service GUID\n");
|
||||
printf("\t (defaults to %s)\n", default_sid);
|
||||
printf("\t--listen: listen forever for incoming AF_HVSOCK connections\n");
|
||||
printf("\t--vsock <port>: use the AF_VSOCK <port>\n");
|
||||
printf("\t--listen: listen forever for incoming AF_VSOCK connections\n");
|
||||
printf("\t--connect: connect to the parent partition\n");
|
||||
}
|
||||
|
||||
@@ -145,8 +206,8 @@ int main(int argc, char **argv)
|
||||
int res = 0;
|
||||
GUID sid;
|
||||
int c;
|
||||
/* Defaults to a testing GUID */
|
||||
char *serviceid = default_sid;
|
||||
unsigned int port = 0;
|
||||
char serviceid[37]; /* 36 for a GUID and 1 for a NULL */
|
||||
char *tag = NULL;
|
||||
char *path = NULL;
|
||||
|
||||
@@ -154,18 +215,22 @@ int main(int argc, char **argv)
|
||||
while (1) {
|
||||
static struct option long_options[] = {
|
||||
/* These options set a flag. */
|
||||
{"serviceid", required_argument, NULL, 's'},
|
||||
{"vsock", required_argument, NULL, 'v'},
|
||||
{"verbose", no_argument, NULL, 'w'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
int option_index = 0;
|
||||
|
||||
c = getopt_long(argc, argv, "s:", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "v:", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 's':
|
||||
serviceid = optarg;
|
||||
case 'v':
|
||||
port = (unsigned int) strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'w':
|
||||
verbose++;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
@@ -206,6 +271,7 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(serviceid, sizeof(serviceid), "%08x-FACB-11E6-BD58-64006A7986D3", port);
|
||||
res = parseguid(serviceid, &sid);
|
||||
if (res) {
|
||||
fprintf(stderr,
|
||||
@@ -214,27 +280,39 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
openlog(argv[0], LOG_CONS | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
|
||||
for (;;) {
|
||||
int lsocket;
|
||||
int sock;
|
||||
int r;
|
||||
|
||||
if (mode == LISTEN) {
|
||||
syslog(LOG_INFO, "starting in listening mode with serviceid=%s, tag=%s, path=%s", serviceid, tag, path);
|
||||
lsocket = create_listening_socket(sid);
|
||||
sock = accept_socket(lsocket);
|
||||
close(lsocket);
|
||||
INFO("starting in listening mode with port=%x, tag=%s, path=%s", port, tag, path);
|
||||
lsocket = create_listening_vsocket(port);
|
||||
if (lsocket != -1) {
|
||||
sock = accept_vsocket(lsocket);
|
||||
close(lsocket);
|
||||
} else {
|
||||
INFO("failed to create AF_VSOCK, trying with AF_HVSOCK serviceid=%s", serviceid);
|
||||
lsocket = create_listening_hvsocket(sid);
|
||||
if (lsocket == -1)
|
||||
fatal("create_listening_vsocket");
|
||||
sock = accept_hvsocket(lsocket);
|
||||
close(lsocket);
|
||||
}
|
||||
} else {
|
||||
syslog(LOG_INFO, "starting in connect mode with serviceid=%s, tag=%s, path=%s", serviceid, tag, path);
|
||||
sock = connect_socket(sid);
|
||||
INFO("starting in connect mode with port=%x, tag=%s, path=%s", port, tag, path);
|
||||
sock = connect_vsocket(port);
|
||||
if (sock == -1) {
|
||||
INFO("failed to connect AF_VSOCK, trying with AF_HVSOCK serviceid=%s", serviceid);
|
||||
sock = connect_hvsocket(sid);
|
||||
}
|
||||
}
|
||||
|
||||
r = handle(sock, tag, path);
|
||||
close(sock);
|
||||
|
||||
if (r == 0) {
|
||||
syslog(LOG_INFO, "mount successful for serviceid=%s tag=%s path=%s", serviceid, tag, path);
|
||||
INFO("mount successful for (serviceid=%s) port=%x tag=%s path=%s", serviceid, port, tag, path);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -242,7 +320,7 @@ int main(int argc, char **argv)
|
||||
* This can happen if the client times out the connection
|
||||
* after we accept it
|
||||
*/
|
||||
syslog(LOG_CRIT, "mount failed with %d for serviceid=%s tag=%s path=%s", r, serviceid, tag, path);
|
||||
ERROR("mount failed with %d for (serviceid=%s) port=%x tag=%s path=%s", r, serviceid, port, tag, path);
|
||||
sleep(1); /* retry */
|
||||
}
|
||||
}
|
||||
|
||||
13
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-9pmount-vsock/log.c
generated
vendored
Normal file
13
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-9pmount-vsock/log.c
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
void fatal(const char *msg)
|
||||
{
|
||||
ERROR("%s Error: %d. %s", msg, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
30
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-9pmount-vsock/log.h
generated
vendored
Normal file
30
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-9pmount-vsock/log.h
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern int verbose;
|
||||
#define ERROR(...) \
|
||||
do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (0)
|
||||
#define INFO(...) \
|
||||
do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (0)
|
||||
#define DBG(...) \
|
||||
do { \
|
||||
if (verbose > 1) { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TRC(...) \
|
||||
do { \
|
||||
if (verbose > 2) { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
extern void fatal(const char *msg);
|
||||
40
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/hvsock.c
generated
vendored
40
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/hvsock.c
generated
vendored
@@ -1,40 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "hvsock.h"
|
||||
|
||||
int parseguid(const char *s, GUID *g)
|
||||
{
|
||||
int res;
|
||||
int p0, p1, p2, p3, p4, p5, p6, p7;
|
||||
|
||||
res = sscanf(s, GUID_FMT,
|
||||
&g->Data1, &g->Data2, &g->Data3,
|
||||
&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7);
|
||||
if (res != 11)
|
||||
return 1;
|
||||
|
||||
g->Data4[0] = p0;
|
||||
g->Data4[1] = p1;
|
||||
g->Data4[2] = p2;
|
||||
g->Data4[3] = p3;
|
||||
g->Data4[4] = p4;
|
||||
g->Data4[5] = p5;
|
||||
g->Data4[6] = p6;
|
||||
g->Data4[7] = p7;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_GUID(HV_GUID_ZERO,
|
||||
0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
DEFINE_GUID(HV_GUID_BROADCAST,
|
||||
0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
|
||||
DEFINE_GUID(HV_GUID_WILDCARD,
|
||||
0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
|
||||
DEFINE_GUID(HV_GUID_CHILDREN,
|
||||
0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd);
|
||||
DEFINE_GUID(HV_GUID_LOOPBACK,
|
||||
0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38);
|
||||
DEFINE_GUID(HV_GUID_PARENT,
|
||||
0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78);
|
||||
48
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/hvsock.h
generated
vendored
48
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/hvsock.h
generated
vendored
@@ -1,48 +0,0 @@
|
||||
/* AF_HYPERV definitions and utilities */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
/* GUID handling */
|
||||
typedef struct _GUID {
|
||||
uint32_t Data1;
|
||||
uint16_t Data2;
|
||||
uint16_t Data3;
|
||||
uint8_t Data4[8];
|
||||
} GUID;
|
||||
|
||||
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
const GUID name = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}
|
||||
|
||||
/* Helper macros for parsing/printing GUIDs */
|
||||
#define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x"
|
||||
#define GUID_ARGS(_g) \
|
||||
(_g).Data1, (_g).Data2, (_g).Data3, \
|
||||
(_g).Data4[0], (_g).Data4[1], (_g).Data4[2], (_g).Data4[3], \
|
||||
(_g).Data4[4], (_g).Data4[5], (_g).Data4[6], (_g).Data4[7]
|
||||
#define GUID_SARGS(_g) \
|
||||
&(_g).Data1, &(_g).Data2, &(_g).Data3, \
|
||||
&(_g).Data4[0], &(_g).Data4[1], &(_g).Data4[2], &(_g).Data4[3], \
|
||||
&(_g).Data4[4], &(_g).Data4[5], &(_g).Data4[6], &(_g).Data4[7]
|
||||
|
||||
extern int parseguid(const char *s, GUID *g);
|
||||
|
||||
/* HV Socket definitions */
|
||||
#define AF_HYPERV 43
|
||||
#define HV_PROTOCOL_RAW 1
|
||||
|
||||
typedef struct _SOCKADDR_HV {
|
||||
unsigned short Family;
|
||||
unsigned short Reserved;
|
||||
GUID VmId;
|
||||
GUID ServiceId;
|
||||
} SOCKADDR_HV;
|
||||
|
||||
extern const GUID HV_GUID_ZERO;
|
||||
extern const GUID HV_GUID_BROADCAST;
|
||||
extern const GUID HV_GUID_WILDCARD;
|
||||
extern const GUID HV_GUID_CHILDREN;
|
||||
extern const GUID HV_GUID_LOOPBACK;
|
||||
extern const GUID HV_GUID_PARENT;
|
||||
13
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/log.c
generated
vendored
Normal file
13
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/log.c
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
void fatal(const char *msg)
|
||||
{
|
||||
ERROR("%s Error: %d. %s", msg, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
30
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/log.h
generated
vendored
Normal file
30
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/log.h
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern int verbose;
|
||||
#define ERROR(...) \
|
||||
do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (0)
|
||||
#define INFO(...) \
|
||||
do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (0)
|
||||
#define DBG(...) \
|
||||
do { \
|
||||
if (verbose > 1) { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TRC(...) \
|
||||
do { \
|
||||
if (verbose > 2) { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
extern void fatal(const char *msg);
|
||||
43
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/protocol.c
generated
vendored
43
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/protocol.c
generated
vendored
@@ -5,8 +5,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "protocol.h"
|
||||
|
||||
/* Version 0 of the protocol used this */
|
||||
@@ -23,13 +23,13 @@ int really_read(int fd, uint8_t *buffer, size_t total)
|
||||
while (remaining > 0) {
|
||||
n = read(fd, buffer, remaining);
|
||||
if (n == 0) {
|
||||
syslog(LOG_CRIT, "EOF reading from socket: closing\n");
|
||||
ERROR("EOF reading from socket: closing\n");
|
||||
goto err;
|
||||
}
|
||||
if (n < 0) {
|
||||
syslog(LOG_CRIT,
|
||||
"Failure reading from socket: closing: %s",
|
||||
strerror(errno));
|
||||
ERROR(
|
||||
"Failure reading from socket: closing: %s",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
remaining -= (size_t) n;
|
||||
@@ -53,13 +53,13 @@ int really_write(int fd, uint8_t *buffer, size_t total)
|
||||
while (remaining > 0) {
|
||||
n = write(fd, buffer, remaining);
|
||||
if (n == 0) {
|
||||
syslog(LOG_CRIT, "EOF writing to socket: closing");
|
||||
ERROR("EOF writing to socket: closing");
|
||||
goto err;
|
||||
}
|
||||
if (n < 0) {
|
||||
syslog(LOG_CRIT,
|
||||
"Failure writing to socket: closing: %s",
|
||||
strerror(errno));
|
||||
ERROR(
|
||||
"Failure writing to socket: closing: %s",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
remaining -= (size_t) n;
|
||||
@@ -117,7 +117,7 @@ int read_init_message(int fd, struct init_message *ci)
|
||||
|
||||
res = really_read(fd, (uint8_t *)&ci->hello[0], sizeof(ci->hello));
|
||||
if (res == -1) {
|
||||
syslog(LOG_CRIT, "Failed to read hello from client");
|
||||
ERROR("Failed to read hello from client");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -131,19 +131,19 @@ int read_init_message(int fd, struct init_message *ci)
|
||||
res = memcmp(&ci->hello[0],
|
||||
&expected_hello[0], sizeof(expected_hello));
|
||||
if (res != 0) {
|
||||
syslog(LOG_CRIT, "Failed to read header magic from client");
|
||||
ERROR("Failed to read header magic from client");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = really_read(fd, (uint8_t *)&ci->version, sizeof(ci->version));
|
||||
if (res == -1) {
|
||||
syslog(LOG_CRIT, "Failed to read header version from client");
|
||||
ERROR("Failed to read header version from client");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = really_read(fd, (uint8_t *)&ci->commit[0], sizeof(ci->commit));
|
||||
if (res == -1) {
|
||||
syslog(LOG_CRIT, "Failed to read header hash from client");
|
||||
ERROR("Failed to read header hash from client");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -156,21 +156,20 @@ int write_init_message(int fd, struct init_message *ci)
|
||||
|
||||
res = really_write(fd, (uint8_t *)&ci->hello[0], sizeof(ci->hello));
|
||||
if (res == -1) {
|
||||
syslog(LOG_CRIT, "Failed to write hello to client");
|
||||
ERROR("Failed to write hello to client");
|
||||
return -1;
|
||||
}
|
||||
if (ci->version > 0) {
|
||||
res = really_write(fd, (uint8_t *)&ci->version,
|
||||
sizeof(ci->version));
|
||||
if (res == -1) {
|
||||
syslog(LOG_CRIT, "Failed to write version to client");
|
||||
ERROR("Failed to write version to client");
|
||||
return -1;
|
||||
}
|
||||
res = really_write(fd, (uint8_t *)&ci->commit[0],
|
||||
sizeof(ci->commit));
|
||||
if (res == -1) {
|
||||
syslog(LOG_CRIT,
|
||||
"Failed to write header hash to client");
|
||||
ERROR("Failed to write header hash to client");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -182,7 +181,7 @@ int read_vif_response(int fd, struct vif_info *vif)
|
||||
struct msg_response msg;
|
||||
|
||||
if (really_read(fd, (uint8_t*)&msg, sizeof(msg)) == -1) {
|
||||
syslog(LOG_CRIT, "Client failed to read server response");
|
||||
ERROR("Client failed to read server response");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -191,10 +190,10 @@ int read_vif_response(int fd, struct vif_info *vif)
|
||||
memcpy((uint8_t*)vif, (uint8_t*)&msg.vif, sizeof(*vif));
|
||||
return 0;
|
||||
case rt_disconnect:
|
||||
syslog(LOG_CRIT, "Server disconnected: %*s", msg.disconnect.len, msg.disconnect.msg);
|
||||
ERROR("Server disconnected: %*s", msg.disconnect.len, msg.disconnect.msg);
|
||||
return -1;
|
||||
default:
|
||||
syslog(LOG_CRIT, "Unknown response type from server");
|
||||
ERROR("Unknown response type from server");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -205,7 +204,7 @@ int write_command(int fd, enum command *c)
|
||||
uint8_t command = *c;
|
||||
|
||||
if (really_write(fd, (uint8_t *)&command, sizeof(command)) == -1) {
|
||||
syslog(LOG_CRIT, "Failed to write command to client");
|
||||
ERROR("Failed to write command to client");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -218,7 +217,7 @@ int write_ethernet_args(int fd, struct ethernet_args *args)
|
||||
memcpy(&buffer[0], (uint8_t *)&args->uuid_string[0], 36);
|
||||
|
||||
if (really_write(fd, (uint8_t *)&buffer, sizeof(buffer)) == -1) {
|
||||
syslog(LOG_CRIT, "Failed to write ethernet args to client");
|
||||
ERROR("Failed to write ethernet args to client");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
205
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/tap-vsockd.c
generated
vendored
205
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/c/vpnkit-tap-vsockd/tap-vsockd.c
generated
vendored
@@ -2,7 +2,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -23,50 +22,19 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include "hvsock.h"
|
||||
#include "protocol.h"
|
||||
#include "ring.h"
|
||||
#include "log.h"
|
||||
|
||||
int daemon_flag;
|
||||
int nofork_flag;
|
||||
int listen_flag;
|
||||
int connect_flag;
|
||||
|
||||
char *default_sid = "30D48B34-7D27-4B0B-AAAF-BBBED334DD59";
|
||||
|
||||
/* Support big frames if the server requests it */
|
||||
const int max_packet_size = 16384;
|
||||
|
||||
static int verbose;
|
||||
#define INFO(...) \
|
||||
do { \
|
||||
if (verbose) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DBG(...) \
|
||||
do { \
|
||||
if (verbose > 1) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TRC(...) \
|
||||
do { \
|
||||
if (verbose > 2) { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void fatal(const char *msg)
|
||||
{
|
||||
syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int alloc_tap(const char *dev)
|
||||
{
|
||||
@@ -88,7 +56,7 @@ int alloc_tap(const char *dev)
|
||||
if (ioctl(fd, TUNSETPERSIST, persist) < 0)
|
||||
fatal("TUNSETPERSIST failed");
|
||||
|
||||
syslog(LOG_INFO, "successfully created TAP device %s", dev);
|
||||
INFO("successfully created TAP device %s", dev);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -147,7 +115,7 @@ int negotiate(int fd, struct vif_info *vif)
|
||||
goto err;
|
||||
|
||||
if (me->version != you.version) {
|
||||
syslog(LOG_CRIT, "Server did not accept our protocol version (client: %d, server: %d)", me->version, you.version);
|
||||
ERROR("Server did not accept our protocol version (client: %d, server: %d)", me->version, you.version);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -155,7 +123,7 @@ int negotiate(int fd, struct vif_info *vif)
|
||||
if (!txt)
|
||||
goto err;
|
||||
|
||||
syslog(LOG_INFO, "Server reports %s", txt);
|
||||
INFO("Server reports %s", txt);
|
||||
free(txt);
|
||||
|
||||
if (write_command(fd, &command) == -1)
|
||||
@@ -171,7 +139,7 @@ int negotiate(int fd, struct vif_info *vif)
|
||||
|
||||
return 0;
|
||||
err:
|
||||
syslog(LOG_CRIT, "Failed to negotiate vmnet connection");
|
||||
ERROR("Failed to negotiate vmnet connection");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -231,14 +199,14 @@ static void* vmnet_to_ring(void *arg)
|
||||
ssize_t n = readv(c->fd, &iovec[0], iovec_len);
|
||||
TRC("vmnet_to_ring: read %zd\n", n);
|
||||
if (n == 0) {
|
||||
syslog(LOG_CRIT, "EOF reading from socket: closing\n");
|
||||
ERROR("EOF reading from socket: closing\n");
|
||||
ring_producer_eof(ring);
|
||||
goto err;
|
||||
}
|
||||
if (n < 0) {
|
||||
syslog(LOG_CRIT,
|
||||
"Failure reading from socket: closing: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
ERROR(
|
||||
"Failure reading from socket: closing: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
ring_producer_eof(ring);
|
||||
goto err;
|
||||
}
|
||||
@@ -280,9 +248,9 @@ static void* ring_to_tap(void *arg)
|
||||
assert(length > 0);
|
||||
TRC("ring_to_tap: packet of length %d\n", length);
|
||||
if (length > max_packet_size) {
|
||||
syslog(LOG_CRIT,
|
||||
"Received an over-large packet: %d > %ld",
|
||||
length, max_packet_size);
|
||||
ERROR(
|
||||
"Received an over-large packet: %d > %d",
|
||||
length, max_packet_size);
|
||||
exit(1);
|
||||
}
|
||||
ring_consumer_advance(ring, 2);
|
||||
@@ -297,8 +265,7 @@ static void* ring_to_tap(void *arg)
|
||||
trim_iovec(iovec, &iovec_len, length);
|
||||
ssize_t n = writev(c->tapfd, &iovec[0], iovec_len);
|
||||
if (n != length) {
|
||||
syslog(LOG_CRIT,
|
||||
"Failed to write %d bytes to tap device (wrote %d)", length, n);
|
||||
ERROR("Failed to write %d bytes to tap device (wrote %zd)", length, n);
|
||||
//exit(1);
|
||||
}
|
||||
TRC("ring_to_tap: ring_consumer_advance n=%zd\n", n);
|
||||
@@ -354,7 +321,7 @@ static void *tap_to_ring(void *arg)
|
||||
if (errno == ENXIO)
|
||||
fatal("tap device has gone down");
|
||||
|
||||
syslog(LOG_WARNING, "ignoring error %d", errno);
|
||||
INFO("ignoring error %d", errno);
|
||||
/*
|
||||
* This is what mirage-net-unix does. Is it a good
|
||||
* idea really?
|
||||
@@ -431,70 +398,29 @@ static void handle(struct connection *connection)
|
||||
fatal("Failed to join the ring_to_vmnet thread");
|
||||
}
|
||||
|
||||
static int create_listening_socket(GUID serviceid)
|
||||
static int connect_unix_socket(char *path)
|
||||
{
|
||||
SOCKADDR_HV sa;
|
||||
int lsock;
|
||||
int res;
|
||||
|
||||
lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
if (lsock == -1)
|
||||
fatal("socket()");
|
||||
|
||||
sa.Family = AF_HYPERV;
|
||||
sa.Reserved = 0;
|
||||
sa.VmId = HV_GUID_WILDCARD;
|
||||
sa.ServiceId = serviceid;
|
||||
|
||||
res = bind(lsock, (const struct sockaddr *)&sa, sizeof(sa));
|
||||
if (res == -1)
|
||||
fatal("bind()");
|
||||
|
||||
res = listen(lsock, SOMAXCONN);
|
||||
if (res == -1)
|
||||
fatal("listen()");
|
||||
|
||||
return lsock;
|
||||
}
|
||||
|
||||
static int connect_socket(GUID serviceid)
|
||||
{
|
||||
SOCKADDR_HV sa;
|
||||
struct sockaddr_un sa;
|
||||
int sock;
|
||||
int res;
|
||||
|
||||
sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock == -1)
|
||||
fatal("socket()");
|
||||
return -1;
|
||||
|
||||
sa.Family = AF_HYPERV;
|
||||
sa.Reserved = 0;
|
||||
sa.VmId = HV_GUID_PARENT;
|
||||
sa.ServiceId = serviceid;
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sun_family = AF_UNIX;
|
||||
strncpy(sa.sun_path, path, sizeof(sa.sun_path)-1);
|
||||
|
||||
res = connect(sock, (const struct sockaddr *)&sa, sizeof(sa));
|
||||
if (res == -1)
|
||||
fatal("connect()");
|
||||
if (res == -1) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static int accept_socket(int lsock)
|
||||
{
|
||||
SOCKADDR_HV sac;
|
||||
socklen_t socklen = sizeof(sac);
|
||||
int csock;
|
||||
|
||||
csock = accept(lsock, (struct sockaddr *)&sac, &socklen);
|
||||
if (csock == -1)
|
||||
fatal("accept()");
|
||||
|
||||
syslog(LOG_INFO, "Connect from: " GUID_FMT ":" GUID_FMT "\n",
|
||||
GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId));
|
||||
|
||||
return csock;
|
||||
}
|
||||
|
||||
void write_pidfile(const char *pidfile)
|
||||
{
|
||||
pid_t pid = getpid();
|
||||
@@ -508,7 +434,7 @@ void write_pidfile(const char *pidfile)
|
||||
len = strlen(pid_s);
|
||||
file = fopen(pidfile, "w");
|
||||
if (file == NULL) {
|
||||
syslog(LOG_CRIT, "Failed to open pidfile %s", pidfile);
|
||||
ERROR("Failed to open pidfile %s", pidfile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -551,53 +477,46 @@ void daemonize(const char *pidfile)
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("%s usage:\n", name);
|
||||
printf("\t[--daemon] [--tap <name>] [--serviceid <guid>] [--pid <file>]\n");
|
||||
printf("\t[--message-size <bytes>] [--buffer-size <bytes>]\n");
|
||||
printf("\t[--listen | --connect]\n\n");
|
||||
printf("\t[--daemon] [--tap <name>] [--path <socket>] [--pid <file>]\n");
|
||||
printf("\t[--message-size <bytes>] [--buffer-size <bytes>]\n\n");
|
||||
printf("where\n");
|
||||
printf("\t--daemonize: run as a background daemon\n");
|
||||
printf("\t--daemon: run as a background daemon\n");
|
||||
printf("\t--nofork: don't run handlers in subprocesses\n");
|
||||
printf("\t--tap <name>: create a tap device with the given name\n");
|
||||
printf("\t (defaults to eth1)\n");
|
||||
printf("\t--serviceid <guid>: use <guid> as the well-known service GUID\n");
|
||||
printf("\t (defaults to %s)\n", default_sid);
|
||||
printf("\t--path <socket>: use <socket> as the path to the vpnkit host server\n");
|
||||
printf("\t--pid <file>: write a pid to the given file\n");
|
||||
printf("\t--message-size <bytes>: dictates the maximum transfer size for AF_HVSOCK\n");
|
||||
printf("\t--buffer-size <bytes>: dictates the buffer size for AF_HVSOCK\n");
|
||||
printf("\t--listen: listen forever for incoming AF_HVSOCK connections\n");
|
||||
printf("\t--connect: connect to the parent partition\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *serviceid = default_sid;
|
||||
char *path = NULL;
|
||||
struct connection connection;
|
||||
char *tap = "eth1";
|
||||
char *pidfile = NULL;
|
||||
int lsocket = -1;
|
||||
char *post_up_script = NULL;
|
||||
int sock = -1;
|
||||
int res = 0;
|
||||
int status;
|
||||
pid_t child;
|
||||
int tapfd;
|
||||
int ring_size = 1048576;
|
||||
int message_size = 8192; /* Well known to work across Hyper-V versions */
|
||||
GUID sid;
|
||||
int c;
|
||||
|
||||
int option_index;
|
||||
int log_flags = LOG_CONS | LOG_NDELAY;
|
||||
static struct option long_options[] = {
|
||||
/* These options set a flag. */
|
||||
{"daemon", no_argument, &daemon_flag, 1},
|
||||
{"nofork", no_argument, &nofork_flag, 1},
|
||||
{"serviceid", required_argument, NULL, 's'},
|
||||
{"path", required_argument, NULL, 'w'},
|
||||
{"tap", required_argument, NULL, 't'},
|
||||
{"pidfile", required_argument, NULL, 'p'},
|
||||
{"listen", no_argument, &listen_flag, 1},
|
||||
{"connect", no_argument, &connect_flag, 1},
|
||||
{"post-up-script", required_argument, NULL, 'x'},
|
||||
{"buffer-size", required_argument, NULL, 'b'},
|
||||
{"message-size", required_argument, NULL, 'm'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -605,7 +524,7 @@ int main(int argc, char **argv)
|
||||
while (1) {
|
||||
option_index = 0;
|
||||
|
||||
c = getopt_long(argc, argv, "ds:t:p:r:m:v",
|
||||
c = getopt_long(argc, argv, "dw:t:p:r:m:v",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
@@ -617,8 +536,8 @@ int main(int argc, char **argv)
|
||||
case 'n':
|
||||
nofork_flag = 1;
|
||||
break;
|
||||
case 's':
|
||||
serviceid = optarg;
|
||||
case 'w':
|
||||
path = optarg;
|
||||
break;
|
||||
case 't':
|
||||
tap = optarg;
|
||||
@@ -626,6 +545,9 @@ int main(int argc, char **argv)
|
||||
case 'p':
|
||||
pidfile = optarg;
|
||||
break;
|
||||
case 'x':
|
||||
post_up_script = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
ring_size = atoi(optarg);
|
||||
break;
|
||||
@@ -643,39 +565,19 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if ((listen_flag && connect_flag) || !(listen_flag || connect_flag)) {
|
||||
fprintf(stderr, "Please supply either the --listen or --connect flag, but not both.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (daemon_flag && !pidfile) {
|
||||
fprintf(stderr, "For daemon mode, please supply a --pidfile argument.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
res = parseguid(serviceid, &sid);
|
||||
if (res) {
|
||||
fprintf(stderr, "Failed to parse serviceid as GUID: %s\n", serviceid);
|
||||
usage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!daemon_flag)
|
||||
log_flags |= LOG_PERROR;
|
||||
|
||||
openlog(argv[0], log_flags, LOG_DAEMON);
|
||||
|
||||
tapfd = alloc_tap(tap);
|
||||
connection.tapfd = tapfd;
|
||||
connection.to_vmnet_ring = ring_allocate(ring_size);
|
||||
connection.from_vmnet_ring = ring_allocate(ring_size);
|
||||
connection.message_size = message_size;
|
||||
if (listen_flag) {
|
||||
syslog(LOG_INFO, "starting in listening mode with serviceid=%s and tap=%s", serviceid, tap);
|
||||
lsocket = create_listening_socket(sid);
|
||||
} else {
|
||||
syslog(LOG_INFO, "starting in connect mode with serviceid=%s and tap=%s", serviceid, tap);
|
||||
}
|
||||
|
||||
INFO("starting in connect mode with path=%s and tap=%s", path, tap);
|
||||
|
||||
|
||||
for (;;) {
|
||||
if (sock != -1) {
|
||||
@@ -683,10 +585,11 @@ int main(int argc, char **argv)
|
||||
sock = -1;
|
||||
}
|
||||
|
||||
if (listen_flag)
|
||||
sock = accept_socket(lsocket);
|
||||
else
|
||||
sock = connect_socket(sid);
|
||||
sock = connect_unix_socket(path);
|
||||
if (sock == -1){
|
||||
sleep(0.1);
|
||||
continue;
|
||||
}
|
||||
|
||||
connection.fd = sock;
|
||||
if (negotiate(sock, &connection.vif) != 0) {
|
||||
@@ -694,13 +597,19 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "VMNET VIF has MAC %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
INFO("VMNET VIF has MAC %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
connection.vif.mac[0], connection.vif.mac[1], connection.vif.mac[2],
|
||||
connection.vif.mac[3], connection.vif.mac[4], connection.vif.mac[5]
|
||||
);
|
||||
set_macaddr(tap, &connection.vif.mac[0]);
|
||||
set_mtu(tap, connection.vif.mtu);
|
||||
|
||||
if (post_up_script) {
|
||||
INFO("Executing post-up-script %s", post_up_script);
|
||||
int result = system(post_up_script);
|
||||
INFO("Result of post-up-script = %d", result);
|
||||
}
|
||||
|
||||
/* Daemonize after we've made our first reliable connection */
|
||||
if (daemon_flag) {
|
||||
daemon_flag = 0;
|
||||
|
||||
51
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/expose_port.go
generated
vendored
Normal file
51
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/expose_port.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ExposePort exposes a port using 9p
|
||||
func ExposePort(host net.Addr, container net.Addr) (*os.File, error) {
|
||||
name := host.Network() + ":" + host.String() + ":" + container.Network() + ":" + container.String()
|
||||
log.Printf("exposePort %s\n", name)
|
||||
err := os.Mkdir("/port/"+name, 0)
|
||||
if err != nil {
|
||||
log.Printf("Failed to mkdir /port/%s: %#v\n", name, err)
|
||||
return nil, err
|
||||
}
|
||||
ctl, err := os.OpenFile("/port/"+name+"/ctl", os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
|
||||
return nil, err
|
||||
}
|
||||
_, err = ctl.WriteString(name)
|
||||
if err != nil {
|
||||
log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
|
||||
return nil, err
|
||||
}
|
||||
_, err = ctl.Seek(0, 0)
|
||||
if err != nil {
|
||||
log.Printf("Failed to seek on /port/%s/ctl: %#v\n", name, err)
|
||||
return nil, err
|
||||
}
|
||||
results := make([]byte, 100)
|
||||
count, err := ctl.Read(results)
|
||||
if err != nil {
|
||||
log.Printf("Failed to read from /port/%s/ctl: %#v\n", name, err)
|
||||
return nil, err
|
||||
}
|
||||
// We deliberately keep the control file open since 9P clunk
|
||||
// will trigger a shutdown on the host side.
|
||||
|
||||
response := string(results[0:count])
|
||||
if strings.HasPrefix(response, "ERROR ") {
|
||||
os.Remove("/port/" + name + "/ctl")
|
||||
response = strings.Trim(response[6:], " \t\r\n")
|
||||
return nil, errors.New(response)
|
||||
}
|
||||
// Hold on to a reference to prevent premature GC and close
|
||||
return ctl, nil
|
||||
}
|
||||
77
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/forward.go
generated
vendored
Normal file
77
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/forward.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Forward a connection to a given destination.
|
||||
func Forward(conn Conn, destination Destination, quit <-chan struct{}) {
|
||||
defer conn.Close()
|
||||
|
||||
switch destination.Proto {
|
||||
case TCP:
|
||||
backendAddr := net.TCPAddr{IP: destination.IP, Port: int(destination.Port), Zone: ""}
|
||||
if err := HandleTCPConnection(conn, &backendAddr, quit); err != nil {
|
||||
log.Printf("closing TCP proxy because %v", err)
|
||||
return
|
||||
}
|
||||
case Unix:
|
||||
backendAddr, err := net.ResolveUnixAddr("unix", destination.Path)
|
||||
if err != nil {
|
||||
log.Printf("Error resolving Unix address %s", destination.Path)
|
||||
return
|
||||
}
|
||||
if err := HandleUnixConnection(conn, backendAddr, quit); err != nil {
|
||||
log.Printf("closing Unix proxy because %v", err)
|
||||
return
|
||||
}
|
||||
case UDP:
|
||||
backendAddr := &net.UDPAddr{IP: destination.IP, Port: int(destination.Port), Zone: ""}
|
||||
// copy to and from the backend without using NewUDPProxy
|
||||
inside, err := net.DialUDP("udp", nil, backendAddr)
|
||||
if err != nil {
|
||||
log.Printf("Failed to Dial UDP backend for %s: %v", backendAddr, err)
|
||||
return
|
||||
}
|
||||
log.Printf("accepted UDP connection to %s\n", backendAddr.String())
|
||||
one := make(chan struct{})
|
||||
two := make(chan struct{})
|
||||
go func() {
|
||||
copyUDP(fmt.Sprintf("from %s to host", backendAddr.String()), inside, conn)
|
||||
close(one)
|
||||
}()
|
||||
go func() {
|
||||
copyUDP(fmt.Sprintf("from host to %s", backendAddr.String()), conn, inside)
|
||||
close(two)
|
||||
}()
|
||||
select {
|
||||
case <-quit: // we want to quit
|
||||
case <-one: // we get an error like "connection refused"
|
||||
case <-two: // we get an error like "connection refused"
|
||||
}
|
||||
log.Printf("closing UDP connection to %s\n", backendAddr.String())
|
||||
_ = inside.Close()
|
||||
return
|
||||
default:
|
||||
log.Printf("Unknown protocol: %d", destination.Proto)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func copyUDP(description string, left, right net.Conn) {
|
||||
b := make([]byte, UDPBufSize)
|
||||
for {
|
||||
n, err := left.Read(b)
|
||||
if err != nil {
|
||||
log.Printf("%s: unable to read UDP: %v", description, err)
|
||||
return
|
||||
}
|
||||
pkt := b[0:n]
|
||||
_, err = right.Write(pkt)
|
||||
if err != nil {
|
||||
log.Printf("%s: unable to write UDP: %v", description, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
443
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/frame.go
generated
vendored
Normal file
443
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/frame.go
generated
vendored
Normal file
@@ -0,0 +1,443 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Proto is the protocol of the flow
|
||||
type Proto uint8
|
||||
|
||||
const (
|
||||
// TCP flow
|
||||
TCP Proto = 1
|
||||
// UDP flow
|
||||
UDP Proto = 2
|
||||
// Unix domain socket flow
|
||||
Unix Proto = 3
|
||||
)
|
||||
|
||||
// Destination refers to a listening TCP or UDP service
|
||||
type Destination struct {
|
||||
Proto Proto
|
||||
IP net.IP
|
||||
Port uint16
|
||||
Path string
|
||||
}
|
||||
|
||||
func (d Destination) String() string {
|
||||
switch d.Proto {
|
||||
case TCP:
|
||||
return fmt.Sprintf("TCP:%s:%d", d.IP.String(), d.Port)
|
||||
case UDP:
|
||||
return fmt.Sprintf("UDP:%s:%d", d.IP.String(), d.Port)
|
||||
case Unix:
|
||||
return fmt.Sprintf("Unix:%s", d.Path)
|
||||
}
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
// Read header which describes TCP/UDP and destination IP:port
|
||||
func unmarshalDestination(r io.Reader) (Destination, error) {
|
||||
d := Destination{}
|
||||
if err := binary.Read(r, binary.LittleEndian, &d.Proto); err != nil {
|
||||
return d, err
|
||||
}
|
||||
switch d.Proto {
|
||||
case TCP, UDP:
|
||||
var length uint16
|
||||
// IP length
|
||||
if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
|
||||
return d, err
|
||||
}
|
||||
d.IP = make([]byte, length)
|
||||
if err := binary.Read(r, binary.LittleEndian, &d.IP); err != nil {
|
||||
return d, err
|
||||
}
|
||||
if err := binary.Read(r, binary.LittleEndian, &d.Port); err != nil {
|
||||
return d, err
|
||||
}
|
||||
case Unix:
|
||||
var length uint16
|
||||
// String length
|
||||
if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
|
||||
return d, err
|
||||
}
|
||||
path := make([]byte, length)
|
||||
if err := binary.Read(r, binary.LittleEndian, &path); err != nil {
|
||||
return d, err
|
||||
}
|
||||
d.Path = string(path)
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d Destination) Write(w io.Writer) error {
|
||||
if err := binary.Write(w, binary.LittleEndian, d.Proto); err != nil {
|
||||
return err
|
||||
}
|
||||
switch d.Proto {
|
||||
case TCP, UDP:
|
||||
b := []byte(d.IP)
|
||||
length := uint16(len(b))
|
||||
if err := binary.Write(w, binary.LittleEndian, length); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, b); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, d.Port); err != nil {
|
||||
return err
|
||||
}
|
||||
case Unix:
|
||||
b := []byte(d.Path)
|
||||
length := uint16(len(b))
|
||||
if err := binary.Write(w, binary.LittleEndian, length); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, b); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Size returns the marshalled size in bytes
|
||||
func (d Destination) Size() int {
|
||||
switch d.Proto {
|
||||
case TCP, UDP:
|
||||
return 1 + 2 + len(d.IP) + 2
|
||||
case Unix:
|
||||
return 1 + 2 + len(d.Path)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Connection indicates whether the connection will use multiplexing or not.
|
||||
type Connection int8
|
||||
|
||||
func (c Connection) String() string {
|
||||
switch c {
|
||||
case Dedicated:
|
||||
return "Dedicated"
|
||||
case Multiplexed:
|
||||
return "Multiplexed"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// Dedicated means this connection will not use multiplexing
|
||||
Dedicated Connection = iota + 1
|
||||
// Multiplexed means this connection will contain labelled sub-connections mixed together
|
||||
Multiplexed
|
||||
)
|
||||
|
||||
// OpenFrame requests to connect to a proxy backend
|
||||
type OpenFrame struct {
|
||||
Connection Connection // Connection describes whether the opened connection should be dedicated or multiplexed
|
||||
Destination Destination
|
||||
}
|
||||
|
||||
func unmarshalOpen(r io.Reader) (*OpenFrame, error) {
|
||||
o := &OpenFrame{}
|
||||
if err := binary.Read(r, binary.LittleEndian, &o.Connection); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d, err := unmarshalDestination(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o.Destination = d
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func (o *OpenFrame) Write(w io.Writer) error {
|
||||
if err := binary.Write(w, binary.LittleEndian, o.Connection); err != nil {
|
||||
return err
|
||||
}
|
||||
return o.Destination.Write(w)
|
||||
}
|
||||
|
||||
// Size returns the marshalled size of the Open message
|
||||
func (o *OpenFrame) Size() int {
|
||||
return 1 + o.Destination.Size()
|
||||
}
|
||||
|
||||
// CloseFrame requests to disconnect from a proxy backend
|
||||
type CloseFrame struct {
|
||||
}
|
||||
|
||||
// ShutdownFrame requests to close the write channel to a proxy backend
|
||||
type ShutdownFrame struct {
|
||||
}
|
||||
|
||||
// DataFrame is the header of a frame containing user data
|
||||
type DataFrame struct {
|
||||
payloadlen uint32
|
||||
}
|
||||
|
||||
func unmarshalData(r io.Reader) (*DataFrame, error) {
|
||||
d := &DataFrame{}
|
||||
err := binary.Read(r, binary.LittleEndian, &d.payloadlen)
|
||||
return d, err
|
||||
}
|
||||
|
||||
func (d *DataFrame) Write(w io.Writer) error {
|
||||
return binary.Write(w, binary.LittleEndian, d.payloadlen)
|
||||
}
|
||||
|
||||
// Size returns the marshalled size of the data payload header
|
||||
func (d *DataFrame) Size() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
// WindowFrame is a window advertisement message
|
||||
type WindowFrame struct {
|
||||
seq uint64
|
||||
}
|
||||
|
||||
func unmarshalWindow(r io.Reader) (*WindowFrame, error) {
|
||||
w := &WindowFrame{}
|
||||
err := binary.Read(r, binary.LittleEndian, &w.seq)
|
||||
return w, err
|
||||
}
|
||||
|
||||
func (win *WindowFrame) Write(w io.Writer) error {
|
||||
return binary.Write(w, binary.LittleEndian, win.seq)
|
||||
}
|
||||
|
||||
// Size returned the marshalled size of the Window payload
|
||||
func (win *WindowFrame) Size() int {
|
||||
return 8
|
||||
}
|
||||
|
||||
// Command is the action requested by a message.
|
||||
type Command int8
|
||||
|
||||
const (
|
||||
// Open requests to open a connection to a backend service.
|
||||
Open Command = iota + 1
|
||||
// Close requests and then acknowledges the close of a sub-connection
|
||||
Close
|
||||
// Shutdown indicates that no more data will be written in this direction
|
||||
Shutdown
|
||||
// Data is a payload of a connection/sub-connection
|
||||
Data
|
||||
// Window is permission to send and consume buffer space
|
||||
Window
|
||||
)
|
||||
|
||||
// Frame is the low-level message sent to the multiplexer
|
||||
type Frame struct {
|
||||
Command Command // Command is the action erquested
|
||||
ID uint32 // Id of the sub-connection, managed by the client
|
||||
open *OpenFrame
|
||||
close *CloseFrame
|
||||
shutdown *ShutdownFrame
|
||||
window *WindowFrame
|
||||
data *DataFrame
|
||||
}
|
||||
|
||||
func unmarshalFrame(r io.Reader) (*Frame, error) {
|
||||
f := &Frame{}
|
||||
var totallen uint16
|
||||
if err := binary.Read(r, binary.LittleEndian, &totallen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := binary.Read(r, binary.LittleEndian, &f.Command); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := binary.Read(r, binary.LittleEndian, &f.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch f.Command {
|
||||
case Open:
|
||||
o, err := unmarshalOpen(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.open = o
|
||||
case Close:
|
||||
// no payload
|
||||
case Shutdown:
|
||||
// no payload
|
||||
case Window:
|
||||
w, err := unmarshalWindow(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.window = w
|
||||
case Data:
|
||||
d, err := unmarshalData(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.data = d
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *Frame) Write(w io.Writer) error {
|
||||
frameLen := uint16(f.Size())
|
||||
if err := binary.Write(w, binary.LittleEndian, frameLen); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, f.Command); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, f.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
switch f.Command {
|
||||
case Open:
|
||||
if err := f.open.Write(w); err != nil {
|
||||
return err
|
||||
}
|
||||
case Close:
|
||||
// no payload
|
||||
case Shutdown:
|
||||
// no payload
|
||||
case Window:
|
||||
if err := f.window.Write(w); err != nil {
|
||||
return err
|
||||
}
|
||||
case Data:
|
||||
if err := f.data.Write(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Size returns the marshalled size of the frame
|
||||
func (f *Frame) Size() int {
|
||||
// include 2 for the preceeding length field
|
||||
len := 2 + 1 + 4
|
||||
switch f.Command {
|
||||
case Open:
|
||||
len = len + f.open.Size()
|
||||
case Close:
|
||||
// no payload
|
||||
case Shutdown:
|
||||
// no payload
|
||||
case Window:
|
||||
len = len + f.window.Size()
|
||||
case Data:
|
||||
len = len + f.data.Size()
|
||||
}
|
||||
return len
|
||||
}
|
||||
|
||||
func (f *Frame) String() string {
|
||||
switch f.Command {
|
||||
case Open:
|
||||
return fmt.Sprintf("%d Open %s %s", f.ID, f.open.Connection.String(), f.open.Destination.String())
|
||||
case Close:
|
||||
return fmt.Sprintf("%d Close", f.ID)
|
||||
case Shutdown:
|
||||
return fmt.Sprintf("%d Shutdown", f.ID)
|
||||
case Window:
|
||||
return fmt.Sprintf("%d Window %d", f.ID, f.window.seq)
|
||||
case Data:
|
||||
return fmt.Sprintf("%d Data length %d", f.ID, f.data.payloadlen)
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Window returns the payload of the frame, if it has Command = Window.
|
||||
func (f *Frame) Window() (*WindowFrame, error) {
|
||||
if f.Command != Window {
|
||||
return nil, errors.New("Frame is not a Window()")
|
||||
}
|
||||
return f.window, nil
|
||||
}
|
||||
|
||||
// Open returns the payload of the frame, if it has Command = Open
|
||||
func (f *Frame) Open() (*OpenFrame, error) {
|
||||
if f.Command != Open {
|
||||
return nil, errors.New("Frame is not an Open()")
|
||||
}
|
||||
return f.open, nil
|
||||
}
|
||||
|
||||
// Data returns the payload of the frame, if it has Command = Data
|
||||
func (f *Frame) Data() (*DataFrame, error) {
|
||||
if f.Command != Data {
|
||||
return nil, errors.New("Frame is not Data()")
|
||||
}
|
||||
return f.data, nil
|
||||
}
|
||||
|
||||
// Payload returns the payload of the frame.
|
||||
func (f *Frame) Payload() interface{} {
|
||||
switch f.Command {
|
||||
case Open:
|
||||
return f.open
|
||||
case Close:
|
||||
return f.close
|
||||
case Shutdown:
|
||||
return f.shutdown
|
||||
case Window:
|
||||
return f.window
|
||||
case Data:
|
||||
return f.data
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewWindow creates a Window message
|
||||
func NewWindow(ID uint32, seq uint64) *Frame {
|
||||
return &Frame{
|
||||
Command: Window,
|
||||
ID: ID,
|
||||
window: &WindowFrame{
|
||||
seq: seq,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewOpen creates an open message
|
||||
func NewOpen(ID uint32, d Destination) *Frame {
|
||||
return &Frame{
|
||||
Command: Open,
|
||||
ID: ID,
|
||||
open: &OpenFrame{
|
||||
Connection: Multiplexed,
|
||||
Destination: d,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewData creates a data header frame
|
||||
func NewData(ID, payloadlen uint32) *Frame {
|
||||
return &Frame{
|
||||
Command: Data,
|
||||
ID: ID,
|
||||
data: &DataFrame{
|
||||
payloadlen: payloadlen,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewShutdown creates a shutdown frame
|
||||
func NewShutdown(ID uint32) *Frame {
|
||||
return &Frame{
|
||||
Command: Shutdown,
|
||||
ID: ID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClose creates a close frame
|
||||
func NewClose(ID uint32) *Frame {
|
||||
return &Frame{
|
||||
Command: Close,
|
||||
ID: ID,
|
||||
}
|
||||
}
|
||||
50
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/handshake.go
generated
vendored
Normal file
50
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/handshake.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type handshake struct {
|
||||
// In future we could add flags here for feature negotiation.
|
||||
// The length is dynamic but it must be < 64k.
|
||||
payload []byte // uninterpreted
|
||||
}
|
||||
|
||||
const handshakeMagic = "https://github.com/moby/vpnkit multiplexer protocol\n"
|
||||
|
||||
func unmarshalHandshake(r io.Reader) (*handshake, error) {
|
||||
magic := make([]byte, len(handshakeMagic))
|
||||
if err := binary.Read(r, binary.LittleEndian, &magic); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if string(magic) != handshakeMagic {
|
||||
return nil, fmt.Errorf("not a connection to a mulitplexer; received bad magic string '%s'", string(magic))
|
||||
}
|
||||
|
||||
var length uint16
|
||||
if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
|
||||
// it will be common to fail here with io.EOF
|
||||
return nil, err
|
||||
}
|
||||
payload := make([]byte, length)
|
||||
if err := binary.Read(r, binary.LittleEndian, &payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &handshake{
|
||||
payload: payload,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *handshake) Write(w io.Writer) error {
|
||||
magic := []byte(handshakeMagic)
|
||||
if err := binary.Write(w, binary.LittleEndian, magic); err != nil {
|
||||
return err
|
||||
}
|
||||
length := uint16(len(h.payload))
|
||||
if err := binary.Write(w, binary.LittleEndian, length); err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(w, binary.LittleEndian, h.payload)
|
||||
}
|
||||
12
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/log.go
generated
vendored
Normal file
12
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/log.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logrus.New()
|
||||
|
||||
// SetLogger sets a new default logger
|
||||
func SetLogger(l *logrus.Logger) {
|
||||
log = l
|
||||
}
|
||||
226
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/loopbackconn.go
generated
vendored
Normal file
226
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/loopbackconn.go
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// io.Pipe is synchronous but we need to decouple the Read and Write calls
|
||||
// with buffering. Adding bufio.NewWriter still requires domeone else to call
|
||||
// `Flush` in a background thread to perform the write. It's simpler to create
|
||||
// our own bufferedPipe out of an array of []byte
|
||||
|
||||
// - each direction within the connection is represented by a bufferedPipe
|
||||
// - each bufferedPipe can be shutdown such that further writes return EOF
|
||||
// and reads return EOF after the buffer is exhausted
|
||||
|
||||
type bufferedPipe struct {
|
||||
bufs [][]byte
|
||||
eof bool
|
||||
m *sync.Mutex
|
||||
c *sync.Cond
|
||||
readDeadline time.Time
|
||||
}
|
||||
|
||||
func newBufferedPipe() *bufferedPipe {
|
||||
var m sync.Mutex
|
||||
c := sync.NewCond(&m)
|
||||
return &bufferedPipe{
|
||||
m: &m,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (pipe *bufferedPipe) TryReadLocked(p []byte) (n int, err error) {
|
||||
// drain buffers before considering EOF
|
||||
if len(pipe.bufs) > 0 {
|
||||
n := copy(p, pipe.bufs[0])
|
||||
pipe.bufs[0] = pipe.bufs[0][n:]
|
||||
|
||||
if len(pipe.bufs[0]) == 0 {
|
||||
// first fragment consumed
|
||||
pipe.bufs = pipe.bufs[1:]
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
if pipe.eof {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (pipe *bufferedPipe) SetReadDeadline(deadline time.Time) error {
|
||||
pipe.m.Lock()
|
||||
defer pipe.m.Unlock()
|
||||
pipe.readDeadline = deadline
|
||||
pipe.c.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
type errTimeout struct {
|
||||
}
|
||||
|
||||
func (e *errTimeout) String() string {
|
||||
return "i/o timeout"
|
||||
}
|
||||
|
||||
func (e *errTimeout) Error() string {
|
||||
return e.String()
|
||||
}
|
||||
|
||||
func (e *errTimeout) Timeout() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *errTimeout) Temporary() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (pipe *bufferedPipe) Read(p []byte) (n int, err error) {
|
||||
pipe.m.Lock()
|
||||
defer pipe.m.Unlock()
|
||||
for {
|
||||
n, err := pipe.TryReadLocked(p)
|
||||
if n > 0 || err != nil {
|
||||
return n, err
|
||||
}
|
||||
done := make(chan struct{})
|
||||
timeout := make(chan time.Time)
|
||||
if !pipe.readDeadline.IsZero() {
|
||||
go func() {
|
||||
time.Sleep(time.Until(pipe.readDeadline))
|
||||
close(timeout)
|
||||
}()
|
||||
}
|
||||
go func() {
|
||||
pipe.c.Wait()
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
case <-timeout:
|
||||
// Clean up the goroutine
|
||||
pipe.c.Broadcast()
|
||||
<-done
|
||||
return n, &errTimeout{}
|
||||
case <-done:
|
||||
// The timeout will still fire in the background
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (pipe *bufferedPipe) Write(p []byte) (n int, err error) {
|
||||
buf := make([]byte, len(p))
|
||||
copy(buf, p)
|
||||
pipe.m.Lock()
|
||||
defer pipe.m.Unlock()
|
||||
if pipe.eof {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
pipe.bufs = append(pipe.bufs, buf)
|
||||
pipe.c.Broadcast()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (pipe *bufferedPipe) closeWriteNoErr() {
|
||||
pipe.m.Lock()
|
||||
defer pipe.m.Unlock()
|
||||
pipe.eof = true
|
||||
pipe.c.Broadcast()
|
||||
}
|
||||
|
||||
func (pipe *bufferedPipe) CloseWrite() error {
|
||||
pipe.closeWriteNoErr()
|
||||
return nil
|
||||
}
|
||||
|
||||
type loopback struct {
|
||||
write *bufferedPipe
|
||||
read *bufferedPipe
|
||||
simulateLatency time.Duration
|
||||
}
|
||||
|
||||
func newLoopback() *loopback {
|
||||
write := newBufferedPipe()
|
||||
read := newBufferedPipe()
|
||||
return &loopback{
|
||||
write: write,
|
||||
read: read,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *loopback) LocalAddr() net.Addr {
|
||||
return &addrLoopback{}
|
||||
}
|
||||
|
||||
func (l *loopback) RemoteAddr() net.Addr {
|
||||
return &addrLoopback{}
|
||||
}
|
||||
|
||||
type addrLoopback struct {
|
||||
}
|
||||
|
||||
func (a *addrLoopback) Network() string {
|
||||
return "loopback"
|
||||
}
|
||||
func (a *addrLoopback) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (l *loopback) SetReadDeadline(timeout time.Time) error {
|
||||
return l.read.SetReadDeadline(timeout)
|
||||
}
|
||||
|
||||
func (l *loopback) SetWriteDeadline(_ time.Time) error {
|
||||
// Writes never block
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *loopback) SetDeadline(timeout time.Time) error {
|
||||
if err := l.SetReadDeadline(timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
return l.SetWriteDeadline(timeout)
|
||||
}
|
||||
|
||||
func (l *loopback) OtherEnd() *loopback {
|
||||
return &loopback{
|
||||
write: l.read,
|
||||
read: l.write,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *loopback) Read(p []byte) (n int, err error) {
|
||||
return l.read.Read(p)
|
||||
}
|
||||
|
||||
func (l *loopback) Write(p []byte) (n int, err error) {
|
||||
n, err = l.write.Write(p)
|
||||
time.Sleep(l.simulateLatency)
|
||||
return
|
||||
}
|
||||
|
||||
func (l *loopback) CloseRead() error {
|
||||
return l.read.CloseWrite()
|
||||
}
|
||||
|
||||
func (l *loopback) CloseWrite() error {
|
||||
return l.write.CloseWrite()
|
||||
}
|
||||
|
||||
func (l *loopback) Close() error {
|
||||
err1 := l.CloseRead()
|
||||
err2 := l.CloseWrite()
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
}
|
||||
|
||||
var _ Conn = &loopback{}
|
||||
635
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/multiplexed.go
generated
vendored
Normal file
635
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/multiplexed.go
generated
vendored
Normal file
@@ -0,0 +1,635 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"container/ring"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
maxBufferSize = 65536
|
||||
)
|
||||
|
||||
type windowState struct {
|
||||
current uint64
|
||||
allowed uint64
|
||||
}
|
||||
|
||||
func (w *windowState) String() string {
|
||||
return fmt.Sprintf("current %d, allowed %d", w.current, w.allowed)
|
||||
}
|
||||
|
||||
func (w *windowState) size() int {
|
||||
return int(w.allowed - w.current)
|
||||
}
|
||||
|
||||
func (w *windowState) isAlmostClosed() bool {
|
||||
return w.size() < maxBufferSize/2
|
||||
}
|
||||
|
||||
func (w *windowState) advance() {
|
||||
w.allowed = w.current + uint64(maxBufferSize)
|
||||
}
|
||||
|
||||
type channel struct {
|
||||
m *sync.Mutex
|
||||
c *sync.Cond
|
||||
multiplexer *multiplexer
|
||||
destination Destination
|
||||
ID uint32
|
||||
read *windowState
|
||||
write *windowState
|
||||
readPipe *bufferedPipe
|
||||
closeReceived bool
|
||||
closeSent bool
|
||||
// initially 2 (sender + receiver), protected by the multiplexer
|
||||
refCount int
|
||||
shutdownSent bool
|
||||
writeDeadline time.Time
|
||||
testAllowDataAfterCloseWrite bool
|
||||
}
|
||||
|
||||
func (c *channel) String() string {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
closeReceived := ""
|
||||
if c.closeReceived {
|
||||
closeReceived = "closeReceived "
|
||||
}
|
||||
closeSent := ""
|
||||
if c.closeSent {
|
||||
closeSent = "closeSent "
|
||||
}
|
||||
shutdownSent := ""
|
||||
if c.shutdownSent {
|
||||
shutdownSent = "shutdownSent "
|
||||
}
|
||||
return fmt.Sprintf("ID %d -> %s %s%s%s", c.ID, c.destination.String(), closeReceived, closeSent, shutdownSent)
|
||||
}
|
||||
|
||||
// newChannel registers a channel through the multiplexer
|
||||
func newChannel(multiplexer *multiplexer, ID uint32, d Destination) *channel {
|
||||
var m sync.Mutex
|
||||
c := sync.NewCond(&m)
|
||||
readPipe := newBufferedPipe()
|
||||
return &channel{
|
||||
m: &m,
|
||||
c: c,
|
||||
multiplexer: multiplexer,
|
||||
destination: d,
|
||||
ID: ID,
|
||||
read: &windowState{},
|
||||
write: &windowState{},
|
||||
readPipe: readPipe,
|
||||
refCount: 2,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *channel) sendWindowUpdate() error {
|
||||
c.m.Lock()
|
||||
c.read.advance()
|
||||
seq := c.read.allowed
|
||||
c.m.Unlock()
|
||||
return c.multiplexer.send(NewWindow(c.ID, seq))
|
||||
}
|
||||
|
||||
func (c *channel) recvWindowUpdate(seq uint64) {
|
||||
c.m.Lock()
|
||||
c.write.allowed = seq
|
||||
c.c.Signal()
|
||||
c.m.Unlock()
|
||||
}
|
||||
|
||||
func (c *channel) Read(p []byte) (int, error) {
|
||||
n, err := c.readPipe.Read(p)
|
||||
c.m.Lock()
|
||||
c.read.current = c.read.current + uint64(n)
|
||||
needUpdate := c.read.isAlmostClosed()
|
||||
c.m.Unlock()
|
||||
if needUpdate {
|
||||
c.sendWindowUpdate()
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// for unit testing only
|
||||
func (c *channel) setTestAllowDataAfterCloseWrite() {
|
||||
c.testAllowDataAfterCloseWrite = true
|
||||
}
|
||||
|
||||
func (c *channel) Write(p []byte) (int, error) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
written := 0
|
||||
for {
|
||||
if len(p) == 0 {
|
||||
return written, nil
|
||||
}
|
||||
if c.closeReceived || c.closeSent || (c.shutdownSent && !c.testAllowDataAfterCloseWrite) {
|
||||
return written, io.EOF
|
||||
}
|
||||
if c.write.size() > 0 {
|
||||
toWrite := c.write.size()
|
||||
if toWrite > len(p) {
|
||||
toWrite = len(p)
|
||||
}
|
||||
// Don't block holding the metadata mutex.
|
||||
// Note this would allow concurrent calls to Write on the same channel
|
||||
// to conflict, but we regard that as user error.
|
||||
c.m.Unlock()
|
||||
|
||||
// need to write the header and the payload together
|
||||
c.multiplexer.writeMutex.Lock()
|
||||
f := NewData(c.ID, uint32(toWrite))
|
||||
c.multiplexer.appendEvent(&event{eventType: eventSend, frame: f})
|
||||
err1 := f.Write(c.multiplexer.connW)
|
||||
_, err2 := c.multiplexer.connW.Write(p[0:toWrite])
|
||||
err3 := c.multiplexer.connW.Flush()
|
||||
c.multiplexer.writeMutex.Unlock()
|
||||
|
||||
c.m.Lock()
|
||||
if err1 != nil {
|
||||
return written, err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return written, err2
|
||||
}
|
||||
if err3 != nil {
|
||||
return written, err3
|
||||
}
|
||||
c.write.current = c.write.current + uint64(toWrite)
|
||||
p = p[toWrite:]
|
||||
written = written + toWrite
|
||||
continue
|
||||
}
|
||||
|
||||
// Wait for the write window to be increased (or a timeout)
|
||||
done := make(chan struct{})
|
||||
timeout := make(chan time.Time)
|
||||
if !c.writeDeadline.IsZero() {
|
||||
go func() {
|
||||
time.Sleep(time.Until(c.writeDeadline))
|
||||
close(timeout)
|
||||
}()
|
||||
}
|
||||
go func() {
|
||||
c.c.Wait()
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
case <-timeout:
|
||||
// clean up the goroutine
|
||||
c.c.Broadcast()
|
||||
<-done
|
||||
return written, &errTimeout{}
|
||||
case <-done:
|
||||
// The timeout will still fire in the background
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *channel) Close() error {
|
||||
// Avoid a Write() racing with us and sending after we Close()
|
||||
// Avoid sending Close twice
|
||||
c.m.Lock()
|
||||
alreadyClosed := c.closeSent
|
||||
c.closeSent = true
|
||||
c.m.Unlock()
|
||||
|
||||
if alreadyClosed {
|
||||
return nil
|
||||
}
|
||||
if err := c.multiplexer.send(NewClose(c.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.c.Broadcast()
|
||||
|
||||
c.multiplexer.decrChannelRef(c.ID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *channel) CloseRead() error {
|
||||
return c.readPipe.CloseWrite()
|
||||
}
|
||||
|
||||
func (c *channel) CloseWrite() error {
|
||||
// Avoid a Write() racing with us and sending after we Close()
|
||||
// Avoid sending Shutdown twice
|
||||
c.m.Lock()
|
||||
alreadyShutdown := c.shutdownSent || c.closeSent
|
||||
c.shutdownSent = true
|
||||
c.m.Unlock()
|
||||
|
||||
if alreadyShutdown {
|
||||
return nil
|
||||
}
|
||||
if err := c.multiplexer.send(NewShutdown(c.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.c.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *channel) recvClose() {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.closeReceived = true
|
||||
c.c.Broadcast()
|
||||
}
|
||||
|
||||
func (c *channel) SetReadDeadline(timeout time.Time) error {
|
||||
return c.readPipe.SetReadDeadline(timeout)
|
||||
}
|
||||
|
||||
func (c *channel) SetWriteDeadline(timeout time.Time) error {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.writeDeadline = timeout
|
||||
c.c.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *channel) SetDeadline(timeout time.Time) error {
|
||||
if err := c.SetReadDeadline(timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.SetWriteDeadline(timeout)
|
||||
}
|
||||
|
||||
func (c *channel) RemoteAddr() net.Addr {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *channel) LocalAddr() net.Addr {
|
||||
return c.RemoteAddr() // There is no local address
|
||||
}
|
||||
|
||||
func (c *channel) Network() string {
|
||||
return "channel"
|
||||
}
|
||||
|
||||
const (
|
||||
eventSend = 0
|
||||
eventRecv = 1
|
||||
eventOpen = 2
|
||||
eventClose = 3
|
||||
)
|
||||
|
||||
type event struct {
|
||||
eventType int
|
||||
frame *Frame // for eventSend and eventRecv
|
||||
id uint32 // for eventOpen and eventClose
|
||||
destination Destination // for eventOpen and eventClose
|
||||
}
|
||||
|
||||
func (e *event) String() string {
|
||||
switch e.eventType {
|
||||
case eventSend:
|
||||
return fmt.Sprintf("send %s", e.frame.String())
|
||||
case eventRecv:
|
||||
return fmt.Sprintf("recv %s", e.frame.String())
|
||||
case eventOpen:
|
||||
return fmt.Sprintf("open %d -> %s", e.id, e.destination)
|
||||
case eventClose:
|
||||
return fmt.Sprintf("close %d -> %s", e.id, e.destination)
|
||||
default:
|
||||
return "unknown trace event"
|
||||
}
|
||||
}
|
||||
|
||||
// Multiplexer muxes and demuxes sub-connections over a single connection
|
||||
type Multiplexer interface {
|
||||
Run() // Run the multiplexer (otherwise Dial, Accept will not work)
|
||||
IsRunning() bool // IsRunning is true if the multiplexer is running normally, false if it has failed
|
||||
|
||||
Dial(d Destination) (Conn, error) // Dial a remote Destination
|
||||
Accept() (Conn, *Destination, error) // Accept a connection from a remote Destination
|
||||
|
||||
Close() error // Close the multiplexer
|
||||
|
||||
DumpState(w io.Writer) // WriteState dumps debug state to the writer
|
||||
}
|
||||
|
||||
type multiplexer struct {
|
||||
label string
|
||||
conn io.Closer
|
||||
connR io.Reader // with buffering
|
||||
connW *bufio.Writer
|
||||
writeMutex *sync.Mutex // hold when writing on the channel
|
||||
channels map[uint32]*channel
|
||||
nextChannelID uint32
|
||||
metadataMutex *sync.Mutex // hold when reading/modifying this structure
|
||||
pendingAccept []*channel // incoming connections
|
||||
acceptCond *sync.Cond
|
||||
isRunning bool
|
||||
events *ring.Ring // log of packetEvents
|
||||
eventsM *sync.Mutex
|
||||
allocateBackwards bool
|
||||
}
|
||||
|
||||
// NewMultiplexer constructs a multiplexer from a channel
|
||||
func NewMultiplexer(label string, conn io.ReadWriteCloser, allocateBackwards bool) (Multiplexer, error) {
|
||||
var writeMutex, metadataMutex, eventsM sync.Mutex
|
||||
acceptCond := sync.NewCond(&metadataMutex)
|
||||
channels := make(map[uint32]*channel)
|
||||
connR := bufio.NewReader(conn)
|
||||
connW := bufio.NewWriter(conn)
|
||||
events := ring.New(500)
|
||||
|
||||
// Perform the handshake
|
||||
localH := &handshake{}
|
||||
|
||||
g := &errgroup.Group{}
|
||||
|
||||
g.Go(func() error { return localH.Write(conn) })
|
||||
g.Go(func() error {
|
||||
_, err := unmarshalHandshake(connR)
|
||||
return err
|
||||
})
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nextId := uint32(0)
|
||||
if allocateBackwards {
|
||||
nextId = ^nextId
|
||||
}
|
||||
return &multiplexer{
|
||||
label: label,
|
||||
conn: conn,
|
||||
connR: connR,
|
||||
connW: connW,
|
||||
writeMutex: &writeMutex,
|
||||
channels: channels,
|
||||
metadataMutex: &metadataMutex,
|
||||
acceptCond: acceptCond,
|
||||
nextChannelID: nextId,
|
||||
events: events,
|
||||
eventsM: &eventsM,
|
||||
allocateBackwards: allocateBackwards,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close the underlying transport.
|
||||
func (m *multiplexer) Close() error {
|
||||
return m.conn.Close()
|
||||
}
|
||||
|
||||
func (m *multiplexer) appendEvent(e *event) {
|
||||
m.eventsM.Lock()
|
||||
defer m.eventsM.Unlock()
|
||||
m.events.Value = e
|
||||
m.events = m.events.Next()
|
||||
}
|
||||
|
||||
func (m *multiplexer) send(f *Frame) error {
|
||||
m.writeMutex.Lock()
|
||||
defer m.writeMutex.Unlock()
|
||||
if err := f.Write(m.connW); err != nil {
|
||||
return err
|
||||
}
|
||||
m.appendEvent(&event{eventType: eventSend, frame: f})
|
||||
return m.connW.Flush()
|
||||
}
|
||||
|
||||
func (m *multiplexer) findFreeChannelID() uint32 {
|
||||
// the metadataMutex is already held
|
||||
if m.allocateBackwards {
|
||||
id := m.nextChannelID
|
||||
for {
|
||||
if _, ok := m.channels[id]; !ok {
|
||||
m.nextChannelID = id - 1
|
||||
return id
|
||||
}
|
||||
id--
|
||||
}
|
||||
}
|
||||
id := m.nextChannelID
|
||||
for {
|
||||
if _, ok := m.channels[id]; !ok {
|
||||
m.nextChannelID = id + 1
|
||||
return id
|
||||
}
|
||||
id++
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiplexer) decrChannelRef(ID uint32) {
|
||||
m.metadataMutex.Lock()
|
||||
defer m.metadataMutex.Unlock()
|
||||
if channel, ok := m.channels[ID]; ok {
|
||||
if channel.refCount == 1 {
|
||||
m.appendEvent(&event{eventType: eventClose, id: ID, destination: channel.destination})
|
||||
delete(m.channels, ID)
|
||||
return
|
||||
}
|
||||
channel.refCount = channel.refCount - 1
|
||||
}
|
||||
}
|
||||
|
||||
// Dial opens a connection to the given destination
|
||||
func (m *multiplexer) Dial(d Destination) (Conn, error) {
|
||||
m.metadataMutex.Lock()
|
||||
if !m.isRunning {
|
||||
m.metadataMutex.Unlock()
|
||||
return nil, errors.New("connection refused")
|
||||
}
|
||||
id := m.findFreeChannelID()
|
||||
channel := newChannel(m, id, d)
|
||||
m.channels[id] = channel
|
||||
m.metadataMutex.Unlock()
|
||||
|
||||
if err := m.send(NewOpen(id, d)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := channel.sendWindowUpdate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if d.Proto == UDP {
|
||||
// remove encapsulation
|
||||
return newUDPConn(channel), nil
|
||||
}
|
||||
return channel, nil
|
||||
}
|
||||
|
||||
// Accept returns the next client connection
|
||||
func (m *multiplexer) Accept() (Conn, *Destination, error) {
|
||||
m.metadataMutex.Lock()
|
||||
defer m.metadataMutex.Unlock()
|
||||
for {
|
||||
if !m.isRunning {
|
||||
return nil, nil, errors.New("accept: multiplexer is not running")
|
||||
}
|
||||
if len(m.pendingAccept) > 0 {
|
||||
first := m.pendingAccept[0]
|
||||
m.pendingAccept = m.pendingAccept[1:]
|
||||
if err := first.sendWindowUpdate(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if first.destination.Proto == UDP {
|
||||
return newUDPConn(first), &first.destination, nil
|
||||
}
|
||||
return first, &first.destination, nil
|
||||
}
|
||||
m.acceptCond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts handling the requests from the other side
|
||||
func (m *multiplexer) Run() {
|
||||
m.metadataMutex.Lock()
|
||||
m.isRunning = true
|
||||
m.metadataMutex.Unlock()
|
||||
go func() {
|
||||
if err := m.run(); err != nil {
|
||||
if err == io.EOF {
|
||||
// This is expected when the data connection is broken
|
||||
log.Infof("disconnected data connection: multiplexer is offline")
|
||||
} else {
|
||||
log.Printf("Multiplexer main loop failed with %v", err)
|
||||
m.DumpState(log.Writer())
|
||||
}
|
||||
}
|
||||
m.metadataMutex.Lock()
|
||||
m.isRunning = false
|
||||
m.acceptCond.Broadcast()
|
||||
var channels []*channel
|
||||
for _, channel := range m.channels {
|
||||
channels = append(channels, channel)
|
||||
}
|
||||
m.metadataMutex.Unlock()
|
||||
|
||||
// close all open channels
|
||||
for _, channel := range channels {
|
||||
// this will unblock waiting Read calls
|
||||
channel.readPipe.closeWriteNoErr()
|
||||
// this will unblock waiting Write calls
|
||||
channel.recvClose()
|
||||
m.decrChannelRef(channel.ID)
|
||||
}
|
||||
|
||||
}()
|
||||
}
|
||||
|
||||
// DumpState writes internal multiplexer state
|
||||
func (m *multiplexer) DumpState(w io.Writer) {
|
||||
m.eventsM.Lock()
|
||||
io.WriteString(w, "Event trace:\n")
|
||||
m.events.Do(func(p interface{}) {
|
||||
if e, ok := p.(*event); ok {
|
||||
io.WriteString(w, e.String())
|
||||
io.WriteString(w, "\n")
|
||||
}
|
||||
})
|
||||
m.eventsM.Unlock()
|
||||
m.metadataMutex.Lock()
|
||||
io.WriteString(w, "Active channels:\n")
|
||||
for _, c := range m.channels {
|
||||
io.WriteString(w, c.String())
|
||||
io.WriteString(w, "\n")
|
||||
}
|
||||
io.WriteString(w, "End of state dump\n")
|
||||
m.metadataMutex.Unlock()
|
||||
}
|
||||
|
||||
// IsRunning returns whether the multiplexer is running or not
|
||||
func (m *multiplexer) IsRunning() bool {
|
||||
m.metadataMutex.Lock()
|
||||
defer m.metadataMutex.Unlock()
|
||||
return m.isRunning
|
||||
}
|
||||
|
||||
func (m *multiplexer) run() error {
|
||||
for {
|
||||
f, err := unmarshalFrame(m.connR)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.appendEvent(&event{eventType: eventRecv, frame: f})
|
||||
switch payload := f.Payload().(type) {
|
||||
case *OpenFrame:
|
||||
o, err := f.Open()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to unmarshal open command: %v", err)
|
||||
}
|
||||
switch o.Connection {
|
||||
case Dedicated:
|
||||
return fmt.Errorf("Dedicated connections are not implemented yet")
|
||||
case Multiplexed:
|
||||
m.metadataMutex.Lock()
|
||||
channel := newChannel(m, f.ID, o.Destination)
|
||||
m.channels[f.ID] = channel
|
||||
m.pendingAccept = append(m.pendingAccept, channel)
|
||||
m.acceptCond.Signal()
|
||||
m.metadataMutex.Unlock()
|
||||
m.appendEvent(&event{eventType: eventOpen, id: f.ID, destination: o.Destination})
|
||||
}
|
||||
case *WindowFrame:
|
||||
m.metadataMutex.Lock()
|
||||
channel, ok := m.channels[f.ID]
|
||||
m.metadataMutex.Unlock()
|
||||
if !ok {
|
||||
return fmt.Errorf("Unknown channel id %s", f.String())
|
||||
}
|
||||
channel.recvWindowUpdate(payload.seq)
|
||||
case *DataFrame:
|
||||
m.metadataMutex.Lock()
|
||||
channel, ok := m.channels[f.ID]
|
||||
m.metadataMutex.Unlock()
|
||||
if !ok {
|
||||
return fmt.Errorf("Unknown channel id: %s", f.String())
|
||||
}
|
||||
// We don't use a direct io.Copy or io.CopyN to the readPipe because if they get
|
||||
// EOF on Write, they will drop the data in the buffer and we don't know how big
|
||||
// it was so we can't avoid desychronising the stream.
|
||||
// We trust the clients not to write more than a Window size.
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.CopyN(&buf, m.connR, int64(payload.payloadlen)); err != nil {
|
||||
return fmt.Errorf("Failed to read payload of %d bytes: %s", payload.payloadlen, f.String())
|
||||
}
|
||||
if n, err := io.Copy(channel.readPipe, &buf); err != nil {
|
||||
// err must be io.EOF
|
||||
log.Printf("Discarded %d bytes from %s", int64(payload.payloadlen)-n, f.String())
|
||||
// A confused client could send a DataFrame after a ShutdownFrame or CloseFrame.
|
||||
// The stream is not desychronised so we can keep going.
|
||||
}
|
||||
case *ShutdownFrame:
|
||||
m.metadataMutex.Lock()
|
||||
channel, ok := m.channels[f.ID]
|
||||
m.metadataMutex.Unlock()
|
||||
if !ok {
|
||||
return fmt.Errorf("Unknown channel id: %s", f.String())
|
||||
}
|
||||
channel.readPipe.closeWriteNoErr()
|
||||
case *CloseFrame:
|
||||
m.metadataMutex.Lock()
|
||||
channel, ok := m.channels[f.ID]
|
||||
m.metadataMutex.Unlock()
|
||||
if !ok {
|
||||
return fmt.Errorf("Unknown channel id: %s", f.String())
|
||||
}
|
||||
// this will unblock waiting Read calls
|
||||
channel.readPipe.closeWriteNoErr()
|
||||
// this will unblock waiting Write calls
|
||||
channel.recvClose()
|
||||
m.decrChannelRef(channel.ID)
|
||||
default:
|
||||
return fmt.Errorf("Unknown command type: %v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/proxy.go
generated
vendored
Normal file
74
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/proxy.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Package libproxy provides a network Proxy interface and implementations for TCP
|
||||
// and UDP.
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Proxy defines the behavior of a proxy. It forwards traffic back and forth
|
||||
// between two endpoints : the frontend and the backend.
|
||||
// It can be used to do software port-mapping between two addresses.
|
||||
// e.g. forward all traffic between the frontend (host) 127.0.0.1:3000
|
||||
// to the backend (container) at 172.17.42.108:4000.
|
||||
type Proxy interface {
|
||||
// Run starts forwarding traffic back and forth between the front
|
||||
// and back-end addresses.
|
||||
Run()
|
||||
// Close stops forwarding traffic and close both ends of the Proxy.
|
||||
Close()
|
||||
// FrontendAddr returns the address on which the proxy is listening.
|
||||
FrontendAddr() net.Addr
|
||||
// BackendAddr returns the proxied address.
|
||||
BackendAddr() net.Addr
|
||||
}
|
||||
|
||||
// NewIPProxy creates a Proxy according to the specified frontendAddr and backendAddr.
|
||||
func NewIPProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
|
||||
switch frontendAddr.(type) {
|
||||
case *net.UDPAddr:
|
||||
listener, err := net.ListenUDP("udp", frontendAddr.(*net.UDPAddr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewUDPProxy(listener.LocalAddr().(*net.UDPAddr), listener, backendAddr.(*net.UDPAddr), nil)
|
||||
case *net.TCPAddr:
|
||||
listener, err := net.Listen("tcp", frontendAddr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewTCPProxy(listener, backendAddr.(*net.TCPAddr))
|
||||
case *net.UnixAddr:
|
||||
listener, err := net.Listen("unix", frontendAddr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewUnixProxy(listener, backendAddr.(*net.UnixAddr))
|
||||
default:
|
||||
panic(fmt.Errorf("Unsupported protocol"))
|
||||
}
|
||||
}
|
||||
|
||||
// NewBestEffortIPProxy Best-effort attempt to listen on the address in the VM. This is for
|
||||
// backwards compatibility with software that expects to be able to listen on
|
||||
// 0.0.0.0 and then connect from within a container to the external port.
|
||||
// If the address doesn't exist in the VM (i.e. it exists only on the host)
|
||||
// then this is not a hard failure.
|
||||
func NewBestEffortIPProxy(host net.Addr, container net.Addr) (Proxy, error) {
|
||||
ipP, err := NewIPProxy(host, container)
|
||||
if err == nil {
|
||||
return ipP, nil
|
||||
}
|
||||
if opError, ok := err.(*net.OpError); ok {
|
||||
if syscallError, ok := opError.Err.(*os.SyscallError); ok {
|
||||
if syscallError.Err == syscall.EADDRNOTAVAIL {
|
||||
log.Printf("Address %s doesn't exist in the VM: only binding on the host", host)
|
||||
return nil, nil // Non-fatal error
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
61
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/stream_proxy.go
generated
vendored
Normal file
61
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/stream_proxy.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Conn defines a network connection
|
||||
type Conn interface {
|
||||
net.Conn
|
||||
CloseWrite() error
|
||||
}
|
||||
|
||||
// ProxyStream data between client and backend, until both are at EOF or quit is closed.
|
||||
func ProxyStream(client, backend Conn, quit <-chan struct{}) error {
|
||||
event := make(chan int64)
|
||||
var broker = func(to, from Conn) {
|
||||
written, err := io.Copy(to, from)
|
||||
if err != nil && err != io.EOF && !errIsBeingClosed(err) {
|
||||
log.Println("error copying:", err)
|
||||
}
|
||||
err = to.CloseWrite()
|
||||
if err != nil && !errIsNotConnected(err) && !errIsBeingClosed(err) {
|
||||
log.Println("error CloseWrite to:", err)
|
||||
}
|
||||
event <- written
|
||||
}
|
||||
|
||||
go broker(client, backend)
|
||||
go broker(backend, client)
|
||||
|
||||
var transferred int64
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case written := <-event:
|
||||
transferred += written
|
||||
case <-quit:
|
||||
// Interrupt the two brokers and "join" them.
|
||||
backend.Close()
|
||||
for ; i < 2; i++ {
|
||||
transferred += <-event
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
backend.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func errIsNotConnected(err error) bool {
|
||||
return strings.HasSuffix(err.Error(), "is not connected")
|
||||
}
|
||||
|
||||
func errIsConnectionRefused(err error) bool {
|
||||
return strings.HasSuffix(err.Error(), "connection refused")
|
||||
}
|
||||
|
||||
func errIsBeingClosed(err error) bool {
|
||||
return strings.HasSuffix(err.Error(), "is being closed.")
|
||||
}
|
||||
31
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/stub_proxy.go
generated
vendored
Normal file
31
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/stub_proxy.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// StubProxy is a proxy that is a stub (does nothing).
|
||||
type StubProxy struct {
|
||||
frontendAddr net.Addr
|
||||
backendAddr net.Addr
|
||||
}
|
||||
|
||||
// Run does nothing.
|
||||
func (p *StubProxy) Run() {}
|
||||
|
||||
// Close does nothing.
|
||||
func (p *StubProxy) Close() {}
|
||||
|
||||
// FrontendAddr returns the frontend address.
|
||||
func (p *StubProxy) FrontendAddr() net.Addr { return p.frontendAddr }
|
||||
|
||||
// BackendAddr returns the backend address.
|
||||
func (p *StubProxy) BackendAddr() net.Addr { return p.backendAddr }
|
||||
|
||||
// NewStubProxy creates a new StubProxy
|
||||
func NewStubProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
|
||||
return &StubProxy{
|
||||
frontendAddr: frontendAddr,
|
||||
backendAddr: backendAddr,
|
||||
}, nil
|
||||
}
|
||||
60
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/tcp_proxy.go
generated
vendored
Normal file
60
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/tcp_proxy.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to
|
||||
// handle TCP traffic forwarding between the frontend and backend addresses.
|
||||
type TCPProxy struct {
|
||||
listener net.Listener
|
||||
frontendAddr net.Addr
|
||||
backendAddr *net.TCPAddr
|
||||
}
|
||||
|
||||
// NewTCPProxy creates a new TCPProxy.
|
||||
func NewTCPProxy(listener net.Listener, backendAddr *net.TCPAddr) (*TCPProxy, error) {
|
||||
// If the port in frontendAddr was 0 then ListenTCP will have a picked
|
||||
// a port to listen on, hence the call to Addr to get that actual port:
|
||||
return &TCPProxy{
|
||||
listener: listener,
|
||||
frontendAddr: listener.Addr(),
|
||||
backendAddr: backendAddr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// HandleTCPConnection forwards the TCP traffic to a specified backend address
|
||||
func HandleTCPConnection(client Conn, backendAddr *net.TCPAddr, quit <-chan struct{}) error {
|
||||
backend, err := net.DialTCP("tcp", nil, backendAddr)
|
||||
if err != nil {
|
||||
if errIsConnectionRefused(err) {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("can't forward traffic to backend tcp/%v: %s", backendAddr, err)
|
||||
}
|
||||
return ProxyStream(client, backend, quit)
|
||||
}
|
||||
|
||||
// Run starts forwarding the traffic using TCP.
|
||||
func (proxy *TCPProxy) Run() {
|
||||
quit := make(chan struct{})
|
||||
defer close(quit)
|
||||
for {
|
||||
client, err := proxy.listener.Accept()
|
||||
if err != nil {
|
||||
log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
|
||||
return
|
||||
}
|
||||
go HandleTCPConnection(client.(Conn), proxy.backendAddr, quit)
|
||||
}
|
||||
}
|
||||
|
||||
// Close stops forwarding the traffic.
|
||||
func (proxy *TCPProxy) Close() { proxy.listener.Close() }
|
||||
|
||||
// FrontendAddr returns the TCP address on which the proxy is listening.
|
||||
func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||
|
||||
// BackendAddr returns the TCP proxied address.
|
||||
func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
||||
202
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/udp_encapsulation.go
generated
vendored
Normal file
202
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/udp_encapsulation.go
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UDPListener defines a listener interface to read, write and close a UDP connection
|
||||
type UDPListener interface {
|
||||
ReadFromUDP(b []byte) (int, *net.UDPAddr, error)
|
||||
WriteToUDP(b []byte, addr *net.UDPAddr) (int, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
// UDPEncapsulator implements net.Conn and reads and writes UDP datagrams framed within a stream connection
|
||||
type uDPEncapsulator interface {
|
||||
Conn
|
||||
ReadFromUDP(b []byte) (int, *net.UDPAddr, error)
|
||||
WriteToUDP(b []byte, addr *net.UDPAddr) (int, error)
|
||||
}
|
||||
|
||||
// udpEncapsulator encapsulates a UDP connection and listener
|
||||
type udpEncapsulator struct {
|
||||
conn net.Conn
|
||||
m *sync.Mutex
|
||||
r *sync.Mutex
|
||||
w *sync.Mutex
|
||||
addr *net.UDPAddr
|
||||
}
|
||||
|
||||
// ReadFromUDP reads the bytestream from a udpEncapsulator, returning the
|
||||
// number of bytes read and the unpacked UDPAddr struct
|
||||
func (u *udpEncapsulator) ReadFromUDP(b []byte) (int, *net.UDPAddr, error) {
|
||||
u.r.Lock()
|
||||
defer u.r.Unlock()
|
||||
datagram := &udpDatagram{payload: b}
|
||||
length, err := datagram.Unmarshal(u.conn)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
udpAddr := net.UDPAddr{IP: *datagram.IP, Port: int(datagram.Port), Zone: datagram.Zone}
|
||||
return length, &udpAddr, nil
|
||||
}
|
||||
|
||||
// WriteToUDP writes a bytestream to a specified UDPAddr, returning the number
|
||||
// of bytes successfully written
|
||||
func (u *udpEncapsulator) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) {
|
||||
u.w.Lock()
|
||||
defer u.w.Unlock()
|
||||
datagram := &udpDatagram{payload: b, IP: &addr.IP, Port: uint16(addr.Port), Zone: addr.Zone}
|
||||
return len(b), datagram.Marshal(u.conn)
|
||||
}
|
||||
|
||||
// Close closes the connection in the udpEncapsulator
|
||||
func (u *udpEncapsulator) Close() error {
|
||||
return u.conn.Close()
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) CloseWrite() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) Read(b []byte) (int, error) {
|
||||
n, _, err := u.ReadFromUDP(b)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) Write(b []byte) (int, error) {
|
||||
return u.WriteToUDP(b, &net.UDPAddr{})
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) LocalAddr() net.Addr {
|
||||
return u.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) RemoteAddr() net.Addr {
|
||||
return u.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) SetDeadline(t time.Time) error {
|
||||
return u.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) SetReadDeadline(t time.Time) error {
|
||||
return u.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) SetWriteDeadline(t time.Time) error {
|
||||
return u.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (u *udpEncapsulator) Connect(a *net.UDPAddr) {
|
||||
u.addr = a
|
||||
}
|
||||
|
||||
// newUDPConn initializes a new UDP connection
|
||||
func newUDPConn(conn net.Conn) uDPEncapsulator {
|
||||
var m sync.Mutex
|
||||
var r sync.Mutex
|
||||
var w sync.Mutex
|
||||
return &udpEncapsulator{
|
||||
conn: conn,
|
||||
m: &m,
|
||||
r: &r,
|
||||
w: &w,
|
||||
}
|
||||
}
|
||||
|
||||
type udpDatagram struct {
|
||||
payload []byte
|
||||
IP *net.IP
|
||||
Port uint16
|
||||
Zone string
|
||||
}
|
||||
|
||||
// Marshal marshals data from the udpDatagram to the provided connection
|
||||
func (u *udpDatagram) Marshal(w io.Writer) error {
|
||||
// marshal the variable length header to a temporary buffer
|
||||
var header bytes.Buffer
|
||||
length := uint16(len(*u.IP))
|
||||
if err := binary.Write(&header, binary.LittleEndian, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(&header, binary.LittleEndian, u.IP); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(&header, binary.LittleEndian, &u.Port); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
length = uint16(len(u.Zone))
|
||||
if err := binary.Write(&header, binary.LittleEndian, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(&header, binary.LittleEndian, []byte(u.Zone)); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
length = uint16(len(u.payload))
|
||||
if err := binary.Write(&header, binary.LittleEndian, &length); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
length = uint16(2 + header.Len() + len(u.payload))
|
||||
if err := binary.Write(w, binary.LittleEndian, &length); err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err := io.Copy(w, &header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
payload := bytes.NewBuffer(u.payload)
|
||||
_, err = io.Copy(w, payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmarshal unmarshals data from the connection to the udpDatagram
|
||||
func (u *udpDatagram) Unmarshal(r io.Reader) (int, error) {
|
||||
var length uint16
|
||||
// frame length
|
||||
if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var IP net.IP
|
||||
IP = make([]byte, length)
|
||||
if err := binary.Read(r, binary.LittleEndian, &IP); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
u.IP = &IP
|
||||
if err := binary.Read(r, binary.LittleEndian, &u.Port); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
Zone := make([]byte, length)
|
||||
if err := binary.Read(r, binary.LittleEndian, &Zone); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
u.Zone = string(Zone)
|
||||
if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_, err := io.ReadFull(r, u.payload[0:length])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(length), nil
|
||||
}
|
||||
178
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/udp_proxy.go
generated
vendored
Normal file
178
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/udp_proxy.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// UDPConnTrackTimeout is the timeout used for UDP connection tracking
|
||||
UDPConnTrackTimeout = 90 * time.Second
|
||||
// UDPBufSize is the buffer size for the UDP proxy
|
||||
UDPBufSize = 65507
|
||||
)
|
||||
|
||||
// A net.Addr where the IP is split into two fields so you can use it as a key
|
||||
// in a map:
|
||||
type connTrackKey struct {
|
||||
IPHigh uint64
|
||||
IPLow uint64
|
||||
Port int
|
||||
}
|
||||
|
||||
func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
|
||||
if len(addr.IP) == net.IPv4len {
|
||||
return &connTrackKey{
|
||||
IPHigh: 0,
|
||||
IPLow: uint64(binary.BigEndian.Uint32(addr.IP)),
|
||||
Port: addr.Port,
|
||||
}
|
||||
}
|
||||
return &connTrackKey{
|
||||
IPHigh: binary.BigEndian.Uint64(addr.IP[:8]),
|
||||
IPLow: binary.BigEndian.Uint64(addr.IP[8:]),
|
||||
Port: addr.Port,
|
||||
}
|
||||
}
|
||||
|
||||
type connTrackMap map[connTrackKey]net.Conn
|
||||
|
||||
// UDPProxy is proxy for which handles UDP datagrams. It implements the Proxy
|
||||
// interface to handle UDP traffic forwarding between the frontend and backend
|
||||
// addresses.
|
||||
type UDPProxy struct {
|
||||
listener UDPListener
|
||||
frontendAddr net.Addr
|
||||
backendAddr *net.UDPAddr
|
||||
dialer UDPDialer
|
||||
connTrackTable connTrackMap
|
||||
connTrackLock sync.Mutex
|
||||
}
|
||||
|
||||
// UDPDialer creates UDP (pseudo-)connections to an address
|
||||
type UDPDialer interface {
|
||||
Dial(*net.UDPAddr) (net.Conn, error)
|
||||
}
|
||||
|
||||
type defaultUDPDialer struct{}
|
||||
|
||||
func (d *defaultUDPDialer) Dial(addr *net.UDPAddr) (net.Conn, error) {
|
||||
return net.DialUDP("udp", nil, addr)
|
||||
}
|
||||
|
||||
// NewUDPProxy creates a new UDPProxy.
|
||||
func NewUDPProxy(frontendAddr net.Addr, listener UDPListener, backendAddr *net.UDPAddr, dialer UDPDialer) (*UDPProxy, error) {
|
||||
if dialer == nil {
|
||||
dialer = &defaultUDPDialer{}
|
||||
}
|
||||
return &UDPProxy{
|
||||
listener: listener,
|
||||
frontendAddr: frontendAddr,
|
||||
backendAddr: backendAddr,
|
||||
dialer: dialer,
|
||||
connTrackTable: make(connTrackMap),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (proxy *UDPProxy) replyLoop(proxyConn net.Conn, clientAddr *net.UDPAddr, clientKey *connTrackKey) {
|
||||
defer func() {
|
||||
proxy.connTrackLock.Lock()
|
||||
delete(proxy.connTrackTable, *clientKey)
|
||||
proxy.connTrackLock.Unlock()
|
||||
proxyConn.Close()
|
||||
}()
|
||||
|
||||
readBuf := make([]byte, UDPBufSize)
|
||||
for {
|
||||
proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout))
|
||||
again:
|
||||
read, err := proxyConn.Read(readBuf)
|
||||
if err != nil {
|
||||
if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
|
||||
// This will happen if the last write failed
|
||||
// (e.g: nothing is actually listening on the
|
||||
// proxied port on the container), ignore it
|
||||
// and continue until UDPConnTrackTimeout
|
||||
// expires:
|
||||
goto again
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i != read; {
|
||||
written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
i += written
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts forwarding the traffic using UDP.
|
||||
func (proxy *UDPProxy) Run() {
|
||||
readBuf := make([]byte, UDPBufSize)
|
||||
for {
|
||||
read, from, err := proxy.listener.ReadFromUDP(readBuf)
|
||||
if err != nil {
|
||||
// NOTE: Apparently ReadFrom doesn't return
|
||||
// ECONNREFUSED like Read do (see comment in
|
||||
// UDPProxy.replyLoop)
|
||||
if !isClosedError(err) {
|
||||
log.Printf("Stopping proxy on %v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
fromKey := newConnTrackKey(from)
|
||||
proxy.connTrackLock.Lock()
|
||||
proxyConn, hit := proxy.connTrackTable[*fromKey]
|
||||
if !hit {
|
||||
proxyConn, err = proxy.dialer.Dial(proxy.backendAddr)
|
||||
if err != nil {
|
||||
log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
|
||||
proxy.connTrackLock.Unlock()
|
||||
continue
|
||||
}
|
||||
proxy.connTrackTable[*fromKey] = proxyConn
|
||||
go proxy.replyLoop(proxyConn, from, fromKey)
|
||||
}
|
||||
proxy.connTrackLock.Unlock()
|
||||
for i := 0; i != read; {
|
||||
written, err := proxyConn.Write(readBuf[i:read])
|
||||
if err != nil {
|
||||
log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
|
||||
break
|
||||
}
|
||||
i += written
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close stops forwarding the traffic.
|
||||
func (proxy *UDPProxy) Close() {
|
||||
proxy.listener.Close()
|
||||
proxy.connTrackLock.Lock()
|
||||
defer proxy.connTrackLock.Unlock()
|
||||
for _, conn := range proxy.connTrackTable {
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// FrontendAddr returns the UDP address on which the proxy is listening.
|
||||
func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||
|
||||
// BackendAddr returns the proxied UDP address.
|
||||
func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
||||
|
||||
func isClosedError(err error) bool {
|
||||
/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing.
|
||||
* See:
|
||||
* http://golang.org/src/pkg/net/net.go
|
||||
* https://code.google.com/p/go/issues/detail?id=4337
|
||||
* https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ
|
||||
*/
|
||||
return strings.HasSuffix(err.Error(), "use of closed network connection")
|
||||
}
|
||||
69
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/unix_proxy.go
generated
vendored
Normal file
69
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/libproxy/unix_proxy.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package libproxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UnixProxy is a proxy for Unix connections. It implements the Proxy interface to
|
||||
// handle Unix traffic forwarding between the frontend and backend addresses.
|
||||
type UnixProxy struct {
|
||||
listener net.Listener
|
||||
frontendAddr net.Addr
|
||||
backendAddr *net.UnixAddr
|
||||
}
|
||||
|
||||
// NewUnixProxy creates a new UnixProxy.
|
||||
func NewUnixProxy(listener net.Listener, backendAddr *net.UnixAddr) (*UnixProxy, error) {
|
||||
log.Printf("NewUnixProxy from %s -> %s\n", listener.Addr().String(), backendAddr.String())
|
||||
return &UnixProxy{
|
||||
listener: listener,
|
||||
frontendAddr: listener.Addr(),
|
||||
backendAddr: backendAddr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// HandleUnixConnection forwards the Unix traffic to a specified backend address
|
||||
func HandleUnixConnection(client Conn, backendAddr *net.UnixAddr, quit <-chan struct{}) error {
|
||||
start := time.Now()
|
||||
for {
|
||||
backend, err := net.DialUnix("unix", nil, backendAddr)
|
||||
if err != nil {
|
||||
if errIsConnectionRefused(err) {
|
||||
if time.Since(start) > 120*time.Second {
|
||||
log.Errorf("failed to connect to %s after 120s. The server appears to be down.", backendAddr.String())
|
||||
return err
|
||||
}
|
||||
log.Infof("%s appears to not be started yet: will retry in 5s", backendAddr.String())
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("can't forward traffic to backend unix/%v: %s", backendAddr, err)
|
||||
}
|
||||
return ProxyStream(client, backend, quit)
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts forwarding the traffic using Unix.
|
||||
func (proxy *UnixProxy) Run() {
|
||||
quit := make(chan struct{})
|
||||
defer close(quit)
|
||||
for {
|
||||
client, err := proxy.listener.Accept()
|
||||
if err != nil {
|
||||
log.Printf("Stopping proxy on unix/%v for unix/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
|
||||
return
|
||||
}
|
||||
go HandleUnixConnection(client.(Conn), proxy.backendAddr, quit)
|
||||
}
|
||||
}
|
||||
|
||||
// Close stops forwarding the traffic.
|
||||
func (proxy *UnixProxy) Close() { proxy.listener.Close() }
|
||||
|
||||
// FrontendAddr returns the Unix address on which the proxy is listening.
|
||||
func (proxy *UnixProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||
|
||||
// BackendAddr returns the Unix proxied address.
|
||||
func (proxy *UnixProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
||||
@@ -1,4 +1,4 @@
|
||||
package vpnkit
|
||||
package vmnet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@@ -21,8 +20,8 @@ type Vmnet struct {
|
||||
remoteVersion *InitMessage
|
||||
}
|
||||
|
||||
// NewVmnet constructs an instance of Vmnet.
|
||||
func NewVmnet(ctx context.Context, path string) (*Vmnet, error) {
|
||||
// New constructs an instance of Vmnet.
|
||||
func New(ctx context.Context, path string) (*Vmnet, error) {
|
||||
d := &net.Dialer{}
|
||||
conn, err := d.DialContext(ctx, "unix", path)
|
||||
if err != nil {
|
||||
@@ -562,24 +561,12 @@ func (v *Vif) dhcp() (net.IP, error) {
|
||||
|
||||
ethernet := NewEthernetFrame(broadcastMAC, v.ClientMAC, 0x800)
|
||||
ethernet.setData(ipv4.Bytes())
|
||||
|
||||
file, err := os.Create("/tmp/go.pcap")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pcap, err := NewPcapWriter(file)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
finished := false
|
||||
go func() {
|
||||
for !finished {
|
||||
if err := v.Write(ethernet.Bytes()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := pcap.Write(ethernet.Bytes()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
@@ -589,9 +576,6 @@ func (v *Vif) dhcp() (net.IP, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := pcap.Write(response); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ethernet, err = ParseEthernetFrame(response)
|
||||
if err != nil {
|
||||
continue
|
||||
134
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/vpnkit/client.go
generated
vendored
Normal file
134
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/vpnkit/client.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package vpnkit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/moby/vpnkit/go/pkg/vpnkit/transport"
|
||||
)
|
||||
|
||||
const (
|
||||
ListPath = "/forwards/list"
|
||||
ExposePortPath = "/forwards/expose/port"
|
||||
ExposePipePath = "/forwards/expose/pipe"
|
||||
UnexposePortPath = "/forwards/unexpose/port"
|
||||
UnexposePipePath = "/forwards/unexpose/pipe"
|
||||
DumpStatePath = "/forwards/dump"
|
||||
)
|
||||
const httpTimeout = 120 * time.Second
|
||||
|
||||
func NewClient(path string) (Client, error) {
|
||||
t := transport.Choose(path)
|
||||
return &httpClient{
|
||||
client: http.Client{
|
||||
Timeout: httpTimeout,
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(c context.Context, _, _ string) (net.Conn, error) {
|
||||
return t.Dial(c, path)
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type httpClient struct {
|
||||
client http.Client
|
||||
}
|
||||
|
||||
// ExposeError should be reported through to the user
|
||||
type ExposeError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (e *ExposeError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func (h *httpClient) Expose(_ context.Context, port *Port) error {
|
||||
var buf bytes.Buffer
|
||||
enc := json.NewEncoder(&buf)
|
||||
if err := enc.Encode(port); err != nil {
|
||||
return err
|
||||
}
|
||||
path := ExposePortPath
|
||||
if port.Proto == Unix {
|
||||
path = ExposePipePath
|
||||
}
|
||||
res, err := h.client.Post("http://unix"+path, "application/json", &buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == 400 {
|
||||
var exposeError ExposeError
|
||||
dec := json.NewDecoder(res.Body)
|
||||
if err := dec.Decode(&exposeError); err != nil {
|
||||
fmt.Printf("failed to decode: %v\n", err)
|
||||
return err
|
||||
}
|
||||
return &exposeError
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf(path+" returned unexpected status: %d", res.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpClient) Unexpose(_ context.Context, port *Port) error {
|
||||
var buf bytes.Buffer
|
||||
enc := json.NewEncoder(&buf)
|
||||
if err := enc.Encode(port); err != nil {
|
||||
return err
|
||||
}
|
||||
path := UnexposePortPath
|
||||
if port.Proto == Unix {
|
||||
path = UnexposePipePath
|
||||
}
|
||||
res, err := h.client.Post("http://unix"+path, "application/json", &buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf(path+" returned unexpected status: %d", res.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpClient) ListExposed(context.Context) ([]Port, error) {
|
||||
res, err := h.client.Get("http://unix" + ListPath)
|
||||
if err != nil {
|
||||
fmt.Printf("GET failed with %v\n", err)
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf(ListPath+" returned unexpected status: %d", res.StatusCode)
|
||||
}
|
||||
dec := json.NewDecoder(res.Body)
|
||||
var ports []Port
|
||||
if err := dec.Decode(&ports); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
func (h *httpClient) DumpState(_ context.Context, w io.Writer) error {
|
||||
res, err := h.client.Get("http://unix" + DumpStatePath)
|
||||
if err != nil {
|
||||
fmt.Printf("GET failed with %v\n", err)
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf(DumpStatePath+" returned unexpected status: %d", res.StatusCode)
|
||||
}
|
||||
_, err = io.Copy(w, res.Body)
|
||||
return err
|
||||
}
|
||||
60
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/vpnkit/config.go
generated
vendored
Normal file
60
src/cmd/linuxkit/vendor/github.com/moby/vpnkit/go/pkg/vpnkit/config.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package vpnkit
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// DHCPConfiguration configures the built-in DHCP server.
|
||||
type DHCPConfiguration struct {
|
||||
SearchDomains []string `json:"searchDomains"`
|
||||
DomainName string `json:"domainName"`
|
||||
}
|
||||
|
||||
func (d DHCPConfiguration) Write(w io.Writer) error {
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
if err := enc.Encode(d); err != nil {
|
||||
return errors.Wrap(err, "while writing DHCPConfiguration")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HTTPConfiguration configures the built-in HTTP proxy.
|
||||
type HTTPConfiguration struct {
|
||||
HTTP string `json:"http,omitempty"`
|
||||
HTTPS string `json:"https,omitempty"`
|
||||
Exclude string `json:"exclude,omitempty"`
|
||||
TransparentHTTPPorts []int `json:"transparent_http_ports"`
|
||||
TransparentHTTPSPorts []int `json:"transparent_https_ports"`
|
||||
}
|
||||
|
||||
func (h HTTPConfiguration) Write(w io.Writer) error {
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
if err := enc.Encode(h); err != nil {
|
||||
return errors.Wrap(err, "while writing HTTPConfiguration")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Forward is a single forward from the gateway IP ExternalPort to (InternalIP, InternalPort)
|
||||
type Forward struct {
|
||||
Protocol Protocol `json:"protocol"`
|
||||
ExternalPort int `json:"external_port"`
|
||||
InternalIP string `json:"internal_ip"`
|
||||
InternalPort int `json:"internal_port"`
|
||||
}
|
||||
|
||||
// GatewayForwards is a list of individual forwards.
|
||||
type GatewayForwards []Forward
|
||||
|
||||
func (g GatewayForwards) Write(w io.Writer) error {
|
||||
enc := json.NewEncoder(w)
|
||||
if err := enc.Encode(g); err != nil {
|
||||
return errors.Wrap(err, "while writing GatewayForewards")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user