TUN-528: Move cloudflared into a separate repo

This commit is contained in:
Areg Harutyunyan
2018-05-01 18:45:06 -05:00
parent e8c621a648
commit d06fc520c7
4726 changed files with 1763680 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["logtransport.go"],
importpath = "zombiezen.com/go/capnproto2/rpc/internal/logtransport",
visibility = ["//rpc:__subpackages__"],
deps = [
"//encoding/text:go_default_library",
"//rpc:go_default_library",
"//rpc/internal/logutil:go_default_library",
"//std/capnp/rpc:go_default_library",
"@org_golang_x_net//context:go_default_library",
],
)

View File

@@ -0,0 +1,52 @@
// Package logtransport provides a transport that logs all of its messages.
package logtransport
import (
"bytes"
"io"
"log"
"golang.org/x/net/context"
"zombiezen.com/go/capnproto2/encoding/text"
"zombiezen.com/go/capnproto2/rpc"
"zombiezen.com/go/capnproto2/rpc/internal/logutil"
rpccapnp "zombiezen.com/go/capnproto2/std/capnp/rpc"
)
type transport struct {
rpc.Transport
l *log.Logger
sendBuf bytes.Buffer
recvBuf bytes.Buffer
}
// New creates a new logger that proxies messages to and from t and
// logs them to l. If l is nil, then the log package's default
// logger is used.
func New(l *log.Logger, t rpc.Transport) rpc.Transport {
return &transport{Transport: t, l: l}
}
func (t *transport) SendMessage(ctx context.Context, msg rpccapnp.Message) error {
t.sendBuf.Reset()
t.sendBuf.WriteString("<- ")
formatMsg(&t.sendBuf, msg)
logutil.Print(t.l, t.sendBuf.String())
return t.Transport.SendMessage(ctx, msg)
}
func (t *transport) RecvMessage(ctx context.Context) (rpccapnp.Message, error) {
msg, err := t.Transport.RecvMessage(ctx)
if err != nil {
return msg, err
}
t.recvBuf.Reset()
t.recvBuf.WriteString("-> ")
formatMsg(&t.recvBuf, msg)
logutil.Print(t.l, t.recvBuf.String())
return msg, nil
}
func formatMsg(w io.Writer, m rpccapnp.Message) {
text.NewEncoder(w).Encode(0x91b79f1f808db032, m.Struct)
}

View File

@@ -0,0 +1,8 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["logutil.go"],
importpath = "zombiezen.com/go/capnproto2/rpc/internal/logutil",
visibility = ["//rpc:__subpackages__"],
)

View File

@@ -0,0 +1,36 @@
// Package logutil provides functions that can print to a logger.
// Any function in this package that takes in a *log.Logger can be
// passed nil to use the log package's default logger.
package logutil
import "log"
// Print calls Print on a logger or the default logger.
// Arguments are handled in the manner of fmt.Print.
func Print(l *log.Logger, v ...interface{}) {
if l == nil {
log.Print(v...)
} else {
l.Print(v...)
}
}
// Printf calls Printf on a logger or the default logger.
// Arguments are handled in the manner of fmt.Printf.
func Printf(l *log.Logger, format string, v ...interface{}) {
if l == nil {
log.Printf(format, v...)
} else {
l.Printf(format, v...)
}
}
// Println calls Println on a logger or the default logger.
// Arguments are handled in the manner of fmt.Println.
func Println(l *log.Logger, v ...interface{}) {
if l == nil {
log.Println(v...)
} else {
l.Println(v...)
}
}

View File

@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["pipetransport.go"],
importpath = "zombiezen.com/go/capnproto2/rpc/internal/pipetransport",
visibility = ["//rpc:__subpackages__"],
deps = [
"//:go_default_library",
"//rpc:go_default_library",
"//std/capnp/rpc:go_default_library",
"@org_golang_x_net//context:go_default_library",
],
)

View File

@@ -0,0 +1,139 @@
// Package pipetransport provides in-memory implementations of rpc.Transport for testing.
package pipetransport
import (
"bytes"
"errors"
"sync"
"golang.org/x/net/context"
"zombiezen.com/go/capnproto2"
"zombiezen.com/go/capnproto2/rpc"
rpccapnp "zombiezen.com/go/capnproto2/std/capnp/rpc"
)
type pipeTransport struct {
r <-chan rpccapnp.Message
w chan<- rpccapnp.Message
finish chan struct{}
otherFin chan struct{}
rbuf bytes.Buffer
mu sync.Mutex
inflight int
done bool
}
// New creates a synchronous in-memory pipe transport.
func New() (p, q rpc.Transport) {
a, b := make(chan rpccapnp.Message), make(chan rpccapnp.Message)
afin, bfin := make(chan struct{}), make(chan struct{})
p = &pipeTransport{
r: a,
w: b,
finish: afin,
otherFin: bfin,
}
q = &pipeTransport{
r: b,
w: a,
finish: bfin,
otherFin: afin,
}
return
}
func (p *pipeTransport) SendMessage(ctx context.Context, msg rpccapnp.Message) error {
if !p.startSend() {
return errClosed
}
defer p.finishSend()
buf, err := msg.Segment().Message().Marshal()
if err != nil {
return err
}
mm, err := capnp.Unmarshal(buf)
if err != nil {
return err
}
msg, err = rpccapnp.ReadRootMessage(mm)
if err != nil {
return err
}
select {
case p.w <- msg:
return nil
case <-ctx.Done():
return ctx.Err()
case <-p.finish:
return errClosed
case <-p.otherFin:
return errBrokenPipe
}
}
func (p *pipeTransport) startSend() bool {
p.mu.Lock()
ok := !p.done
if ok {
p.inflight++
}
p.mu.Unlock()
return ok
}
func (p *pipeTransport) finishSend() {
p.mu.Lock()
p.inflight--
p.mu.Unlock()
}
func (p *pipeTransport) RecvMessage(ctx context.Context) (rpccapnp.Message, error) {
// Scribble over shared buffer to test for race conditions.
for b, i := p.rbuf.Bytes(), 0; i < len(b); i++ {
b[i] = 0xff
}
p.rbuf.Reset()
select {
case msg, ok := <-p.r:
if !ok {
return rpccapnp.Message{}, errBrokenPipe
}
if err := capnp.NewEncoder(&p.rbuf).Encode(msg.Segment().Message()); err != nil {
return rpccapnp.Message{}, err
}
m, err := capnp.Unmarshal(p.rbuf.Bytes())
if err != nil {
return rpccapnp.Message{}, err
}
return rpccapnp.ReadRootMessage(m)
case <-ctx.Done():
return rpccapnp.Message{}, ctx.Err()
}
}
func (p *pipeTransport) Close() error {
p.mu.Lock()
done := p.done
if !done {
p.done = true
close(p.finish)
if p.inflight == 0 {
close(p.w)
}
}
p.mu.Unlock()
if done {
return errClosed
}
return nil
}
var (
errBrokenPipe = errors.New("pipetransport: broken pipe")
errClosed = errors.New("pipetransport: write to broken pipe")
)

View File

@@ -0,0 +1,16 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["refcount.go"],
importpath = "zombiezen.com/go/capnproto2/rpc/internal/refcount",
visibility = ["//rpc:__subpackages__"],
deps = ["//:go_default_library"],
)
go_test(
name = "go_default_test",
srcs = ["refcount_test.go"],
embed = [":go_default_library"],
deps = ["//:go_default_library"],
)

View File

@@ -0,0 +1,116 @@
// Package refcount implements a reference-counting client.
package refcount
import (
"errors"
"runtime"
"sync"
"zombiezen.com/go/capnproto2"
)
// A RefCount will close its underlying client once all its references are closed.
type RefCount struct {
Client capnp.Client
mu sync.Mutex
refs int
}
// New creates a reference counter and the first client reference.
func New(c capnp.Client) (rc *RefCount, ref1 capnp.Client) {
if rr, ok := c.(*Ref); ok {
return rr.rc, rr.rc.Ref()
}
rc = &RefCount{Client: c, refs: 1}
ref1 = rc.newRef()
return
}
// Ref makes a new client reference.
func (rc *RefCount) Ref() capnp.Client {
rc.mu.Lock()
if rc.refs <= 0 {
rc.mu.Unlock()
return capnp.ErrorClient(errZeroRef)
}
rc.refs++
rc.mu.Unlock()
return rc.newRef()
}
func (rc *RefCount) newRef() *Ref {
r := &Ref{rc: rc}
runtime.SetFinalizer(r, (*Ref).Close)
return r
}
func (rc *RefCount) call(cl *capnp.Call) capnp.Answer {
// We lock here so that we can prevent the client from being closed
// while we start the call.
rc.mu.Lock()
if rc.refs <= 0 {
rc.mu.Unlock()
return capnp.ErrorAnswer(errClosed)
}
ans := rc.Client.Call(cl)
rc.mu.Unlock()
return ans
}
// decref decreases the reference count by one, closing the Client if it reaches zero.
func (rc *RefCount) decref() error {
shouldClose := false
rc.mu.Lock()
if rc.refs <= 0 {
rc.mu.Unlock()
return errClosed
}
rc.refs--
if rc.refs == 0 {
shouldClose = true
}
rc.mu.Unlock()
if shouldClose {
return rc.Client.Close()
}
return nil
}
var (
errZeroRef = errors.New("rpc: Ref() called on zeroed refcount")
errClosed = errors.New("rpc: Close() called on closed client")
)
// A Ref is a single reference to a client wrapped by RefCount.
type Ref struct {
rc *RefCount
once sync.Once
}
// Call makes a call on the underlying client.
func (r *Ref) Call(cl *capnp.Call) capnp.Answer {
return r.rc.call(cl)
}
// Client returns the underlying client.
func (r *Ref) Client() capnp.Client {
return r.rc.Client
}
// Close decrements the reference count. Close will be called on
// finalization (i.e. garbage collection).
func (r *Ref) Close() error {
var err error
closed := false
r.once.Do(func() {
err = r.rc.decref()
closed = true
})
if !closed {
return errClosed
}
return err
}

View File

@@ -0,0 +1,89 @@
package refcount
import (
"testing"
"zombiezen.com/go/capnproto2"
)
func TestSingleRefCloses(t *testing.T) {
c := new(fakeClient)
_, ref := New(c)
err := ref.Close()
if err != nil {
t.Errorf("ref.Close(): %v", err)
}
if c.closed != 1 {
t.Errorf("client Close() called %d times; want 1 time", c.closed)
}
}
func TestCloseRefMultipleDecrefsOnce(t *testing.T) {
c := new(fakeClient)
rc, ref1 := New(c)
ref2 := rc.Ref()
err1 := ref1.Close()
err2 := ref1.Close()
_ = ref2
if err1 != nil {
t.Errorf("ref.Close() #1: %v", err1)
}
if err2 != errClosed {
t.Errorf("ref.Close() #2: %v; want %v", err2, errClosed)
}
if c.closed != 0 {
t.Errorf("client Close() called %d times; want 0 times", c.closed)
}
}
func TestClosingOneOfManyRefsDoesntClose(t *testing.T) {
c := new(fakeClient)
rc, ref1 := New(c)
ref2 := rc.Ref()
err := ref1.Close()
_ = ref2
if err != nil {
t.Errorf("ref1.Close(): %v", err)
}
if c.closed != 0 {
t.Errorf("client Close() called %d times; want 0 times", c.closed)
}
}
func TestClosingAllRefsCloses(t *testing.T) {
c := new(fakeClient)
rc, ref1 := New(c)
ref2 := rc.Ref()
err1 := ref1.Close()
err2 := ref2.Close()
if err1 != nil {
t.Errorf("ref1.Close(): %v", err1)
}
if err2 != nil {
t.Errorf("ref2.Close(): %v", err2)
}
if c.closed != 1 {
t.Errorf("client Close() called %d times; want 1 times", c.closed)
}
}
type fakeClient struct {
closed int
}
func (c *fakeClient) Call(cl *capnp.Call) capnp.Answer {
panic("not implemented")
}
func (c *fakeClient) Close() error {
c.closed++
return nil
}

View File

@@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"generate.go",
"test.capnp.go",
],
importpath = "zombiezen.com/go/capnproto2/rpc/internal/testcapnp",
visibility = ["//rpc:__subpackages__"],
deps = [
"//:go_default_library",
"//encoding/text:go_default_library",
"//schemas:go_default_library",
"//server:go_default_library",
"@org_golang_x_net//context:go_default_library",
],
)

View File

@@ -0,0 +1,3 @@
package testcapnp
//go:generate capnp compile -I ../../../std -ogo test.capnp

View File

@@ -0,0 +1,40 @@
# Test interfaces for RPC tests.
using Go = import "/go.capnp";
@0xef12a34b9807e19c;
$Go.package("testcapnp");
$Go.import("zombiezen.com/go/capnproto2/rpc/internal/testcapnp");
interface Handle {}
interface HandleFactory {
newHandle @0 () -> (handle :Handle);
}
interface Hanger {
hang @0 () -> ();
# Block until context is cancelled
}
interface CallOrder {
getCallSequence @0 (expected: UInt32) -> (n: UInt32);
# First call returns 0, next returns 1, ...
#
# The input `expected` is ignored but useful for disambiguating debug logs.
}
interface Echoer extends(CallOrder) {
echo @0 (cap :CallOrder) -> (cap :CallOrder);
# Just returns the input cap.
}
interface PingPong {
echoNum @0 (n :Int32) -> (n :Int32);
}
# Example interfaces
interface Adder {
add @0 (a :Int32, b :Int32) -> (result :Int32);
}

File diff suppressed because it is too large Load Diff