TUN-1604: Define Connect RPC call
This commit is contained in:
parent
8560436487
commit
8c6cfa34aa
|
@ -186,12 +186,12 @@
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:8f8811f9be822914c3a25c6a071e93beb4c805d7b026cbf298bc577bc1cc945b"
|
digest = "1:582b704bebaa06b48c29b0cec224a6058a09c86883aaddabde889cd1a5f73e1b"
|
||||||
name = "github.com/google/uuid"
|
name = "github.com/google/uuid"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "064e2069ce9c359c118179501254f67d7d37ba24"
|
revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
|
||||||
version = "0.2"
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1"
|
digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1"
|
||||||
|
|
|
@ -2,8 +2,10 @@ package pogs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"zombiezen.com/go/capnproto2"
|
"zombiezen.com/go/capnproto2"
|
||||||
|
@ -71,6 +73,80 @@ func UnmarshalRegistrationOptions(s tunnelrpc.RegistrationOptions) (*Registratio
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServerHello struct {
|
||||||
|
ConnectResult *ConnectResult
|
||||||
|
CloudflaredID uuid.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapnpServerHello is ServerHello respresented in Cap'n Proto build-in types
|
||||||
|
type CapnpServerHello struct {
|
||||||
|
ConnectResult *ConnectResult
|
||||||
|
CloudflaredID []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func MarshalServerHello(s tunnelrpc.CapnpServerHello, p *ServerHello) error {
|
||||||
|
cloudflaredIDBytes, err := p.CloudflaredID.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
capnpServerHello := &CapnpServerHello{
|
||||||
|
ConnectResult: p.ConnectResult,
|
||||||
|
CloudflaredID: cloudflaredIDBytes,
|
||||||
|
}
|
||||||
|
return pogs.Insert(tunnelrpc.CapnpServerHello_TypeID, s.Struct, capnpServerHello)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalServerHello(s tunnelrpc.CapnpServerHello) (*ServerHello, error) {
|
||||||
|
p := new(CapnpServerHello)
|
||||||
|
err := pogs.Extract(p, tunnelrpc.CapnpServerHello_TypeID, s.Struct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cloudflaredID, err := uuid.FromBytes(p.CloudflaredID)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("fail to unmarshal %+v", p.CloudflaredID)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ServerHello{
|
||||||
|
ConnectResult: p.ConnectResult,
|
||||||
|
CloudflaredID: cloudflaredID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectResult struct {
|
||||||
|
Err *ConnectError
|
||||||
|
ServerInfo ServerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func MarshalConnectResult(s tunnelrpc.ConnectResult, p *ConnectResult) error {
|
||||||
|
return pogs.Insert(tunnelrpc.ConnectResult_TypeID, s.Struct, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalConnectResult(s tunnelrpc.ConnectResult) (*ConnectResult, error) {
|
||||||
|
p := new(ConnectResult)
|
||||||
|
err := pogs.Extract(p, tunnelrpc.ConnectResult_TypeID, s.Struct)
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectError struct {
|
||||||
|
Cause string
|
||||||
|
RetryAfter time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func MarshalConnectError(s tunnelrpc.ConnectError, p *ConnectError) error {
|
||||||
|
return pogs.Insert(tunnelrpc.ConnectError_TypeID, s.Struct, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalConnectError(s tunnelrpc.ConnectError) (*ConnectError, error) {
|
||||||
|
p := new(ConnectError)
|
||||||
|
err := pogs.Extract(p, tunnelrpc.ConnectError_TypeID, s.Struct)
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ConnectError) Error() string {
|
||||||
|
return e.Cause
|
||||||
|
}
|
||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
|
@ -90,10 +166,71 @@ func UnmarshalServerInfo(s tunnelrpc.ServerInfo) (*ServerInfo, error) {
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HelloParameters struct {
|
||||||
|
OriginCert []byte
|
||||||
|
Tags []Tag
|
||||||
|
NumPreviousAttempts uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func MarshalHelloParameters(s tunnelrpc.HelloParameters, p *HelloParameters) error {
|
||||||
|
return pogs.Insert(tunnelrpc.HelloParameters_TypeID, s.Struct, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalHelloParameters(s tunnelrpc.HelloParameters) (*HelloParameters, error) {
|
||||||
|
p := new(HelloParameters)
|
||||||
|
err := pogs.Extract(p, tunnelrpc.HelloParameters_TypeID, s.Struct)
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectParameters struct {
|
||||||
|
OriginCert []byte
|
||||||
|
CloudflaredID uuid.UUID
|
||||||
|
NumPreviousAttempts uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapnpConnectParameters is ConnectParameters represented in Cap'n Proto build-in types
|
||||||
|
type CapnpConnectParameters struct {
|
||||||
|
OriginCert []byte
|
||||||
|
CloudflaredID []byte
|
||||||
|
NumPreviousAttempts uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func MarshalConnectParameters(s tunnelrpc.CapnpConnectParameters, p *ConnectParameters) error {
|
||||||
|
cloudflaredIDBytes, err := p.CloudflaredID.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
capnpConnectParameters := &CapnpConnectParameters{
|
||||||
|
OriginCert: p.OriginCert,
|
||||||
|
CloudflaredID: cloudflaredIDBytes,
|
||||||
|
NumPreviousAttempts: p.NumPreviousAttempts,
|
||||||
|
}
|
||||||
|
return pogs.Insert(tunnelrpc.CapnpConnectParameters_TypeID, s.Struct, capnpConnectParameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalConnectParameters(s tunnelrpc.CapnpConnectParameters) (*ConnectParameters, error) {
|
||||||
|
p := new(CapnpConnectParameters)
|
||||||
|
err := pogs.Extract(p, tunnelrpc.CapnpConnectParameters_TypeID, s.Struct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cloudflaredID, err := uuid.FromBytes(p.CloudflaredID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ConnectParameters{
|
||||||
|
OriginCert: p.OriginCert,
|
||||||
|
CloudflaredID: cloudflaredID,
|
||||||
|
NumPreviousAttempts: p.NumPreviousAttempts,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type TunnelServer interface {
|
type TunnelServer interface {
|
||||||
RegisterTunnel(ctx context.Context, originCert []byte, hostname string, options *RegistrationOptions) (*TunnelRegistration, error)
|
RegisterTunnel(ctx context.Context, originCert []byte, hostname string, options *RegistrationOptions) (*TunnelRegistration, error)
|
||||||
GetServerInfo(ctx context.Context) (*ServerInfo, error)
|
GetServerInfo(ctx context.Context) (*ServerInfo, error)
|
||||||
UnregisterTunnel(ctx context.Context, gracePeriodNanoSec int64) error
|
UnregisterTunnel(ctx context.Context, gracePeriodNanoSec int64) error
|
||||||
|
Hello(ctx context.Context, parameters *HelloParameters) (*ServerHello, error)
|
||||||
|
Connect(ctx context.Context, paramaters *ConnectParameters) (*ConnectResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TunnelServer_ServerToClient(s TunnelServer) tunnelrpc.TunnelServer {
|
func TunnelServer_ServerToClient(s TunnelServer) tunnelrpc.TunnelServer {
|
||||||
|
@ -151,7 +288,48 @@ func (i TunnelServer_PogsImpl) UnregisterTunnel(p tunnelrpc.TunnelServer_unregis
|
||||||
gracePeriodNanoSec := p.Params.GracePeriodNanoSec()
|
gracePeriodNanoSec := p.Params.GracePeriodNanoSec()
|
||||||
server.Ack(p.Options)
|
server.Ack(p.Options)
|
||||||
return i.impl.UnregisterTunnel(p.Ctx, gracePeriodNanoSec)
|
return i.impl.UnregisterTunnel(p.Ctx, gracePeriodNanoSec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i TunnelServer_PogsImpl) Hello(p tunnelrpc.TunnelServer_hello) error {
|
||||||
|
parameters, err := p.Params.Parameters()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pogsParameters, err := UnmarshalHelloParameters(parameters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
server.Ack(p.Options)
|
||||||
|
serverHello, err := i.impl.Hello(p.Ctx, pogsParameters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
result, err := p.Results.NewResult()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return MarshalServerHello(result, serverHello)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i TunnelServer_PogsImpl) Connect(p tunnelrpc.TunnelServer_connect) error {
|
||||||
|
paramaters, err := p.Params.Parameters()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pogsParameters, err := UnmarshalConnectParameters(paramaters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
server.Ack(p.Options)
|
||||||
|
connectResult, err := i.impl.Connect(p.Ctx, pogsParameters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
result, err := p.Results.NewResult()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return MarshalConnectResult(result, connectResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TunnelServer_PogsClient struct {
|
type TunnelServer_PogsClient struct {
|
||||||
|
@ -212,3 +390,47 @@ func (c TunnelServer_PogsClient) UnregisterTunnel(ctx context.Context, gracePeri
|
||||||
_, err := promise.Struct()
|
_, err := promise.Struct()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c TunnelServer_PogsClient) Hello(ctx context.Context,
|
||||||
|
parameters *HelloParameters,
|
||||||
|
) (*ServerHello, error) {
|
||||||
|
client := tunnelrpc.TunnelServer{Client: c.Client}
|
||||||
|
promise := client.Hello(ctx, func(p tunnelrpc.TunnelServer_hello_Params) error {
|
||||||
|
helloParameters, err := p.NewParameters()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = MarshalHelloParameters(helloParameters, parameters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
retval, err := promise.Result().Struct()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return UnmarshalServerHello(retval)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c TunnelServer_PogsClient) Connect(ctx context.Context,
|
||||||
|
parameters *ConnectParameters,
|
||||||
|
) (*ConnectResult, error) {
|
||||||
|
client := tunnelrpc.TunnelServer{Client: c.Client}
|
||||||
|
promise := client.Connect(ctx, func(p tunnelrpc.TunnelServer_connect_Params) error {
|
||||||
|
connectParameters, err := p.NewParameters()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = MarshalConnectParameters(connectParameters, parameters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
retval, err := promise.Result().Struct()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return UnmarshalConnectResult(retval)
|
||||||
|
}
|
||||||
|
|
|
@ -46,6 +46,43 @@ struct RegistrationOptions {
|
||||||
uuid @11 :Text;
|
uuid @11 :Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct HelloParameters {
|
||||||
|
# certificate and token to prove ownership of a zone
|
||||||
|
originCert @0 :Data;
|
||||||
|
# user defined labels for this cloudflared
|
||||||
|
tags @1 :List(Tag);
|
||||||
|
# number of previous attempts to send Hello
|
||||||
|
numPreviousAttempts @2 :UInt8;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CapnpConnectParameters {
|
||||||
|
# certificate and token to prove ownership of a zone
|
||||||
|
originCert @0 :Data;
|
||||||
|
# UUID assigned to this cloudflared obtained from Hello
|
||||||
|
cloudflaredID @1 :Data;
|
||||||
|
# number of previous attempts to send Connect
|
||||||
|
numPreviousAttempts @2 :UInt8;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CapnpServerHello {
|
||||||
|
connectResult @0 :ConnectResult;
|
||||||
|
# UUID assigned to this cloudflared
|
||||||
|
cloudflaredID @1 :Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ConnectResult {
|
||||||
|
err @0 :ConnectError;
|
||||||
|
# Information about the server this connection is established with
|
||||||
|
serverInfo @1 :ServerInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ConnectError {
|
||||||
|
cause @0 :Text;
|
||||||
|
# How long should this connection wait to retry in ns
|
||||||
|
retryAfter @1 :Int64;
|
||||||
|
shoudRetry @2 :Bool;
|
||||||
|
}
|
||||||
|
|
||||||
struct Tag {
|
struct Tag {
|
||||||
name @0 :Text;
|
name @0 :Text;
|
||||||
value @1 :Text;
|
value @1 :Text;
|
||||||
|
@ -65,4 +102,8 @@ interface TunnelServer {
|
||||||
registerTunnel @0 (originCert :Data, hostname :Text, options :RegistrationOptions) -> (result :TunnelRegistration);
|
registerTunnel @0 (originCert :Data, hostname :Text, options :RegistrationOptions) -> (result :TunnelRegistration);
|
||||||
getServerInfo @1 () -> (result :ServerInfo);
|
getServerInfo @1 () -> (result :ServerInfo);
|
||||||
unregisterTunnel @2 (gracePeriodNanoSec :Int64) -> ();
|
unregisterTunnel @2 (gracePeriodNanoSec :Int64) -> ();
|
||||||
|
# originCert is used to verify ownership of a zone and hostnames it can serve
|
||||||
|
# tags are client-defined tags to associate with the cloudflared
|
||||||
|
hello @3(parameters :HelloParameters) -> (result: CapnpServerHello);
|
||||||
|
connect @4(parameters :CapnpConnectParameters) -> (result :ConnectResult);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,3 @@
|
||||||
**This package is currently in development and the API may not be stable.**
|
|
||||||
|
|
||||||
The API will become stable with v1.
|
|
||||||
|
|
||||||
# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master)
|
# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master)
|
||||||
The uuid package generates and inspects UUIDs based on
|
The uuid package generates and inspects UUIDs based on
|
||||||
[RFC 4122](http://tools.ietf.org/html/rfc4122)
|
[RFC 4122](http://tools.ietf.org/html/rfc4122)
|
||||||
|
|
|
@ -42,7 +42,7 @@ func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||||
// domain with the id returned by os.Getuid.
|
// domain with the id returned by os.Getuid.
|
||||||
//
|
//
|
||||||
// NewDCEPerson(Person, uint32(os.Getuid()))
|
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||||
func NewDCEPerson() (UUID, error) {
|
func NewDCEPerson() (UUID, error) {
|
||||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func NewDCEPerson() (UUID, error) {
|
||||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||||
// domain with the id returned by os.Getgid.
|
// domain with the id returned by os.Getgid.
|
||||||
//
|
//
|
||||||
// NewDCEGroup(Group, uint32(os.Getgid()))
|
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||||
func NewDCEGroup() (UUID, error) {
|
func NewDCEGroup() (UUID, error) {
|
||||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
module github.com/google/uuid
|
|
@ -27,7 +27,7 @@ var (
|
||||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||||
h.Reset()
|
h.Reset()
|
||||||
h.Write(space[:])
|
h.Write(space[:])
|
||||||
h.Write([]byte(data))
|
h.Write(data)
|
||||||
s := h.Sum(nil)
|
s := h.Sum(nil)
|
||||||
var uuid UUID
|
var uuid UUID
|
||||||
copy(uuid[:], s)
|
copy(uuid[:], s)
|
||||||
|
|
|
@ -15,8 +15,6 @@ func (uuid UUID) MarshalText() ([]byte, error) {
|
||||||
|
|
||||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
func (uuid *UUID) UnmarshalText(data []byte) error {
|
func (uuid *UUID) UnmarshalText(data []byte) error {
|
||||||
// See comment in ParseBytes why we do this.
|
|
||||||
// id, err := ParseBytes(data)
|
|
||||||
id, err := ParseBytes(data)
|
id, err := ParseBytes(data)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
*uuid = id
|
*uuid = id
|
||||||
|
|
|
@ -5,13 +5,11 @@
|
||||||
package uuid
|
package uuid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
nodeMu sync.Mutex
|
nodeMu sync.Mutex
|
||||||
interfaces []net.Interface // cached list of interfaces
|
|
||||||
ifname string // name of interface being used
|
ifname string // name of interface being used
|
||||||
nodeID [6]byte // hardware for version 1 UUIDs
|
nodeID [6]byte // hardware for version 1 UUIDs
|
||||||
zeroID [6]byte // nodeID with only 0's
|
zeroID [6]byte // nodeID with only 0's
|
||||||
|
@ -39,26 +37,18 @@ func SetNodeInterface(name string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNodeInterface(name string) bool {
|
func setNodeInterface(name string) bool {
|
||||||
if interfaces == nil {
|
iname, addr := getHardwareInterface(name) // null implementation for js
|
||||||
var err error
|
if iname != "" && addr != nil {
|
||||||
interfaces, err = net.Interfaces()
|
ifname = iname
|
||||||
if err != nil && name != "" {
|
copy(nodeID[:], addr)
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ifs := range interfaces {
|
|
||||||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
|
||||||
copy(nodeID[:], ifs.HardwareAddr)
|
|
||||||
ifname = ifs.Name
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// We found no interfaces with a valid hardware address. If name
|
// We found no interfaces with a valid hardware address. If name
|
||||||
// does not specify a specific interface generate a random Node ID
|
// does not specify a specific interface generate a random Node ID
|
||||||
// (section 4.1.6)
|
// (section 4.1.6)
|
||||||
if name == "" {
|
if name == "" {
|
||||||
|
ifname = "random"
|
||||||
randomBits(nodeID[:])
|
randomBits(nodeID[:])
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -94,9 +84,6 @@ func SetNodeID(id []byte) bool {
|
||||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||||
func (uuid UUID) NodeID() []byte {
|
func (uuid UUID) NodeID() []byte {
|
||||||
if len(uuid) != 16 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var node [6]byte
|
var node [6]byte
|
||||||
copy(node[:], uuid[10:])
|
copy(node[:], uuid[10:])
|
||||||
return node[:]
|
return node[:]
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build js
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
// getHardwareInterface returns nil values for the JS version of the code.
|
||||||
|
// This remvoves the "net" dependency, because it is not used in the browser.
|
||||||
|
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||||
|
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !js
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
var interfaces []net.Interface // cached list of interfaces
|
||||||
|
|
||||||
|
// getHardwareInterface returns the name and hardware address of interface name.
|
||||||
|
// If name is "" then the name and hardware address of one of the system's
|
||||||
|
// interfaces is returned. If no interfaces are found (name does not exist or
|
||||||
|
// there are no interfaces) then "", nil is returned.
|
||||||
|
//
|
||||||
|
// Only addresses of at least 6 bytes are returned.
|
||||||
|
func getHardwareInterface(name string) (string, []byte) {
|
||||||
|
if interfaces == nil {
|
||||||
|
var err error
|
||||||
|
interfaces, err = net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, ifs := range interfaces {
|
||||||
|
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||||
|
return ifs.Name, ifs.HardwareAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
|
@ -13,35 +13,36 @@ import (
|
||||||
// Currently, database types that map to string and []byte are supported. Please
|
// Currently, database types that map to string and []byte are supported. Please
|
||||||
// consult database-specific driver documentation for matching types.
|
// consult database-specific driver documentation for matching types.
|
||||||
func (uuid *UUID) Scan(src interface{}) error {
|
func (uuid *UUID) Scan(src interface{}) error {
|
||||||
switch src.(type) {
|
switch src := src.(type) {
|
||||||
|
case nil:
|
||||||
|
return nil
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
// if an empty UUID comes from a table, we return a null UUID
|
// if an empty UUID comes from a table, we return a null UUID
|
||||||
if src.(string) == "" {
|
if src == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// see Parse for required string format
|
// see Parse for required string format
|
||||||
u, err := Parse(src.(string))
|
u, err := Parse(src)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Scan: %v", err)
|
return fmt.Errorf("Scan: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
*uuid = u
|
*uuid = u
|
||||||
case []byte:
|
|
||||||
b := src.([]byte)
|
|
||||||
|
|
||||||
|
case []byte:
|
||||||
// if an empty UUID comes from a table, we return a null UUID
|
// if an empty UUID comes from a table, we return a null UUID
|
||||||
if len(b) == 0 {
|
if len(src) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes a simple slice of bytes if 16 bytes
|
// assumes a simple slice of bytes if 16 bytes
|
||||||
// otherwise attempts to parse
|
// otherwise attempts to parse
|
||||||
if len(b) != 16 {
|
if len(src) != 16 {
|
||||||
return uuid.Scan(string(b))
|
return uuid.Scan(string(src))
|
||||||
}
|
}
|
||||||
copy((*uuid)[:], b)
|
copy((*uuid)[:], src)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||||
|
|
|
@ -86,7 +86,7 @@ func clockSequence() int {
|
||||||
return int(clockSeq & 0x3fff)
|
return int(clockSeq & 0x3fff)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
|
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||||
// -1 causes a new sequence to be generated.
|
// -1 causes a new sequence to be generated.
|
||||||
func SetClockSequence(seq int) {
|
func SetClockSequence(seq int) {
|
||||||
defer timeMu.Unlock()
|
defer timeMu.Unlock()
|
||||||
|
@ -100,9 +100,9 @@ func setClockSequence(seq int) {
|
||||||
randomBits(b[:]) // clock sequence
|
randomBits(b[:]) // clock sequence
|
||||||
seq = int(b[0])<<8 | int(b[1])
|
seq = int(b[0])<<8 | int(b[1])
|
||||||
}
|
}
|
||||||
old_seq := clockSeq
|
oldSeq := clockSeq
|
||||||
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||||
if old_seq != clockSeq {
|
if oldSeq != clockSeq {
|
||||||
lasttime = 0
|
lasttime = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2016 Google Inc. All rights reserved.
|
// Copyright 2018 Google Inc. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -35,20 +35,43 @@ const (
|
||||||
|
|
||||||
var rander = rand.Reader // random function
|
var rander = rand.Reader // random function
|
||||||
|
|
||||||
// Parse decodes s into a UUID or returns an error. Both the UUID form of
|
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
||||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
|
||||||
|
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
|
||||||
|
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
|
||||||
func Parse(s string) (UUID, error) {
|
func Parse(s string) (UUID, error) {
|
||||||
var uuid UUID
|
var uuid UUID
|
||||||
if len(s) != 36 {
|
switch len(s) {
|
||||||
if len(s) != 36+9 {
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
case 36:
|
||||||
}
|
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36 + 9:
|
||||||
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
||||||
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||||
}
|
}
|
||||||
s = s[9:]
|
s = s[9:]
|
||||||
|
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
case 36 + 2:
|
||||||
|
s = s[1:]
|
||||||
|
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
case 32:
|
||||||
|
var ok bool
|
||||||
|
for i := range uuid {
|
||||||
|
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
default:
|
||||||
|
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
||||||
|
}
|
||||||
|
// s is now at least 36 bytes long
|
||||||
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||||
return uuid, errors.New("invalid UUID format")
|
return uuid, errors.New("invalid UUID format")
|
||||||
}
|
}
|
||||||
|
@ -58,11 +81,11 @@ func Parse(s string) (UUID, error) {
|
||||||
14, 16,
|
14, 16,
|
||||||
19, 21,
|
19, 21,
|
||||||
24, 26, 28, 30, 32, 34} {
|
24, 26, 28, 30, 32, 34} {
|
||||||
if v, ok := xtob(s[x], s[x+1]); !ok {
|
v, ok := xtob(s[x], s[x+1])
|
||||||
|
if !ok {
|
||||||
return uuid, errors.New("invalid UUID format")
|
return uuid, errors.New("invalid UUID format")
|
||||||
} else {
|
|
||||||
uuid[i] = v
|
|
||||||
}
|
}
|
||||||
|
uuid[i] = v
|
||||||
}
|
}
|
||||||
return uuid, nil
|
return uuid, nil
|
||||||
}
|
}
|
||||||
|
@ -70,15 +93,29 @@ func Parse(s string) (UUID, error) {
|
||||||
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||||
func ParseBytes(b []byte) (UUID, error) {
|
func ParseBytes(b []byte) (UUID, error) {
|
||||||
var uuid UUID
|
var uuid UUID
|
||||||
if len(b) != 36 {
|
switch len(b) {
|
||||||
if len(b) != 36+9 {
|
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
}
|
|
||||||
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
|
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
|
||||||
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||||
}
|
}
|
||||||
b = b[9:]
|
b = b[9:]
|
||||||
|
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
b = b[1:]
|
||||||
|
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
var ok bool
|
||||||
|
for i := 0; i < 32; i += 2 {
|
||||||
|
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
default:
|
||||||
|
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
||||||
|
}
|
||||||
|
// s is now at least 36 bytes long
|
||||||
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||||
return uuid, errors.New("invalid UUID format")
|
return uuid, errors.New("invalid UUID format")
|
||||||
}
|
}
|
||||||
|
@ -88,15 +125,32 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||||
14, 16,
|
14, 16,
|
||||||
19, 21,
|
19, 21,
|
||||||
24, 26, 28, 30, 32, 34} {
|
24, 26, 28, 30, 32, 34} {
|
||||||
if v, ok := xtob(b[x], b[x+1]); !ok {
|
v, ok := xtob(b[x], b[x+1])
|
||||||
|
if !ok {
|
||||||
return uuid, errors.New("invalid UUID format")
|
return uuid, errors.New("invalid UUID format")
|
||||||
} else {
|
}
|
||||||
uuid[i] = v
|
uuid[i] = v
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return uuid, nil
|
return uuid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||||
|
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||||
|
func MustParse(s string) UUID {
|
||||||
|
uuid, err := Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||||
|
// does not have a length of 16. The bytes are copied from the slice.
|
||||||
|
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||||
|
err = uuid.UnmarshalBinary(b)
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
// Must returns uuid if err is nil and panics otherwise.
|
// Must returns uuid if err is nil and panics otherwise.
|
||||||
func Must(uuid UUID, err error) UUID {
|
func Must(uuid UUID, err error) UUID {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -123,7 +177,7 @@ func (uuid UUID) URN() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeHex(dst []byte, uuid UUID) {
|
func encodeHex(dst []byte, uuid UUID) {
|
||||||
hex.Encode(dst[:], uuid[:4])
|
hex.Encode(dst, uuid[:4])
|
||||||
dst[8] = '-'
|
dst[8] = '-'
|
||||||
hex.Encode(dst[9:13], uuid[4:6])
|
hex.Encode(dst[9:13], uuid[4:6])
|
||||||
dst[13] = '-'
|
dst[13] = '-'
|
||||||
|
@ -176,7 +230,7 @@ func (v Variant) String() string {
|
||||||
return fmt.Sprintf("BadVariant%d", int(v))
|
return fmt.Sprintf("BadVariant%d", int(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRand sets the random number generator to r, which implents io.Reader.
|
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||||
// If r.Read returns an error when the package requests random data then
|
// If r.Read returns an error when the package requests random data then
|
||||||
// a panic will be issued.
|
// a panic will be issued.
|
||||||
//
|
//
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||||
// be set NewUUID returns nil. If clock sequence has not been set by
|
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||||
// return the current NewUUID returns Nil and an error.
|
// return the current NewUUID returns nil and an error.
|
||||||
//
|
//
|
||||||
// In most cases, New should be used.
|
// In most cases, New should be used.
|
||||||
func NewUUID() (UUID, error) {
|
func NewUUID() (UUID, error) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ package uuid
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
|
||||||
// New is creates a new random UUID or panics. New is equivalent to
|
// New creates a new random UUID or panics. New is equivalent to
|
||||||
// the expression
|
// the expression
|
||||||
//
|
//
|
||||||
// uuid.Must(uuid.NewRandom())
|
// uuid.Must(uuid.NewRandom())
|
||||||
|
@ -14,12 +14,12 @@ func New() UUID {
|
||||||
return Must(NewRandom())
|
return Must(NewRandom())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRandom returns a Random (Version 4) UUID or panics.
|
// NewRandom returns a Random (Version 4) UUID.
|
||||||
//
|
//
|
||||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||||
// package.
|
// package.
|
||||||
//
|
//
|
||||||
// A note about uniqueness derived from from the UUID Wikipedia entry:
|
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||||
//
|
//
|
||||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||||
|
|
Loading…
Reference in New Issue