mirror of
https://github.com/linka-cloud/grpc.git
synced 2025-11-24 05:03:16 +00:00
feat(server/client): add windows pipe, pipe peer credentials support
Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
This commit is contained in:
@@ -3,6 +3,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
@@ -19,7 +20,7 @@ type Client interface {
|
||||
}
|
||||
|
||||
func New(opts ...Option) (Client, error) {
|
||||
c := &client{opts: &options{}}
|
||||
c := &client{opts: &options{dialOptions: []grpc.DialOption{grpc.WithContextDialer(dial)}}}
|
||||
for _, o := range opts {
|
||||
o(c.opts)
|
||||
}
|
||||
@@ -78,3 +79,32 @@ func (c *client) Invoke(ctx context.Context, method string, args interface{}, re
|
||||
func (c *client) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||
return c.cc.NewStream(ctx, desc, method, opts...)
|
||||
}
|
||||
|
||||
func parseDialTarget(target string) (string, string) {
|
||||
net := "tcp"
|
||||
m1 := strings.Index(target, ":")
|
||||
m2 := strings.Index(target, ":/")
|
||||
// handle unix:addr which will fail with url.Parse
|
||||
if m1 >= 0 && m2 < 0 {
|
||||
if n := target[0:m1]; n == "unix" {
|
||||
return n, target[m1+1:]
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(target, `\\.\pipe\`) {
|
||||
net = "pipe"
|
||||
return net, target
|
||||
}
|
||||
if m2 >= 0 {
|
||||
t, err := url.Parse(target)
|
||||
if err != nil {
|
||||
return net, target
|
||||
}
|
||||
scheme := t.Scheme
|
||||
addr := t.Host
|
||||
if scheme == "unix" {
|
||||
addr += t.Path
|
||||
}
|
||||
return scheme, addr
|
||||
}
|
||||
return net, target
|
||||
}
|
||||
|
||||
26
client/client_test.go
Normal file
26
client/client_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseDialTarget(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expectedNet string
|
||||
expectedAddr string
|
||||
}{
|
||||
{"tcp://localhost:50051", "tcp", "localhost:50051"},
|
||||
{"localhost:50051", "tcp", "localhost:50051"},
|
||||
{"unix:///tmp/socket", "unix", "/tmp/socket"},
|
||||
{"unix://C:/path/to/socket", "unix", "C:/path/to/socket"},
|
||||
{"unix:path/to/socket", "unix", "path/to/socket"},
|
||||
{`\\.\pipe\example`, "pipe", `\\.\pipe\example`},
|
||||
}
|
||||
for _, test := range tests {
|
||||
net, addr := parseDialTarget(test.input)
|
||||
if net != test.expectedNet || addr != test.expectedAddr {
|
||||
t.Errorf("parseDialTarget(%q) = (%q, %q); want (%q, %q)", test.input, net, addr, test.expectedNet, test.expectedAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
12
client/dialer.go
Normal file
12
client/dialer.go
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build !windows
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
func dial(ctx context.Context, addr string) (net.Conn, error) {
|
||||
network, address := parseDialTarget(addr)
|
||||
return (&net.Dialer{}).DialContext(ctx, network, address)
|
||||
}
|
||||
18
client/dialer_windows.go
Normal file
18
client/dialer_windows.go
Normal file
@@ -0,0 +1,18 @@
|
||||
//go:build windows
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
)
|
||||
|
||||
func dial(ctx context.Context, addr string) (net.Conn, error) {
|
||||
network, address := parseDialTarget(addr)
|
||||
if network == "pipe" {
|
||||
return winio.DialPipeContext(ctx, address)
|
||||
}
|
||||
return (&net.Dialer{}).DialContext(ctx, network, address)
|
||||
}
|
||||
@@ -2,15 +2,36 @@ package peercreds
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/soheilhy/cmux"
|
||||
"github.com/tailscale/peercred"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
var ErrUnsupportedConnType = peercred.ErrUnsupportedConnType
|
||||
|
||||
var _ credentials.TransportCredentials = (*peerCreds)(nil)
|
||||
|
||||
// Creds are the peer credentials.
|
||||
type Creds struct {
|
||||
pid int
|
||||
uid string
|
||||
}
|
||||
|
||||
func (c *Creds) PID() (pid int, ok bool) {
|
||||
return c.pid, c.pid != 0
|
||||
}
|
||||
|
||||
// UserID returns the userid (or Windows SID) that owns the other side
|
||||
// of the connection, if known. (ok is false if not known)
|
||||
// The returned string is suitable to passing to os/user.LookupId.
|
||||
func (c *Creds) UserID() (uid string, ok bool) {
|
||||
return c.uid, c.uid != ""
|
||||
}
|
||||
|
||||
var common = credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity}
|
||||
|
||||
func New() credentials.TransportCredentials {
|
||||
@@ -27,12 +48,12 @@ type peerCreds struct {
|
||||
// AuthInfo we’ll attach to the gRPC peer
|
||||
type AuthInfo struct {
|
||||
credentials.CommonAuthInfo
|
||||
Creds *peercred.Creds
|
||||
Creds Creds
|
||||
}
|
||||
|
||||
func (AuthInfo) AuthType() string { return "peercred" }
|
||||
|
||||
func (t *peerCreds) ClientHandshake(_ context.Context, _ string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||
func (t *peerCreds) ClientHandshake(ctx context.Context, authority string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||
return t.handshakeConn(conn)
|
||||
}
|
||||
|
||||
@@ -54,15 +75,30 @@ func (t *peerCreds) OverrideServerName(name string) error {
|
||||
}
|
||||
|
||||
func (t *peerCreds) handshakeConn(conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||
if conn.RemoteAddr().Network() != "unix" {
|
||||
return nil, nil, errors.New("peercred only works with unix domain sockets")
|
||||
if conn.RemoteAddr().Network() != "unix" && conn.RemoteAddr().Network() != "pipe" {
|
||||
return nil, nil, errors.New("peercred only works with unix domain sockets or Windows named pipes")
|
||||
}
|
||||
creds, err := peercred.Get(conn)
|
||||
inner := conn
|
||||
unwrap:
|
||||
for {
|
||||
switch c := inner.(type) {
|
||||
case *cmux.MuxConn:
|
||||
inner = c.Conn
|
||||
case *tls.Conn:
|
||||
inner = c.NetConn()
|
||||
default:
|
||||
break unwrap
|
||||
}
|
||||
}
|
||||
creds, err := Get(inner)
|
||||
if err != nil {
|
||||
if errors.Is(err, peercred.ErrNotImplemented) {
|
||||
return nil, nil, errors.New("peercred not implemented on this OS")
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
return conn, AuthInfo{Creds: creds, CommonAuthInfo: common}, nil
|
||||
var c Creds
|
||||
c.uid, _ = creds.UserID()
|
||||
c.pid, _ = creds.PID()
|
||||
return conn, AuthInfo{Creds: c, CommonAuthInfo: common}, nil
|
||||
}
|
||||
|
||||
20
creds/peercreds/peercreds_unix.go
Normal file
20
creds/peercreds/peercreds_unix.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build !windows
|
||||
|
||||
package peercreds
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/tailscale/peercred"
|
||||
)
|
||||
|
||||
func Get(conn net.Conn) (*Creds, error) {
|
||||
creds, err := peercred.Get(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var c Creds
|
||||
c.uid, _ = creds.UserID()
|
||||
c.pid, _ = creds.PID()
|
||||
return &c, nil
|
||||
}
|
||||
134
creds/peercreds/peercreds_windows.go
Normal file
134
creds/peercreds/peercreds_windows.go
Normal file
@@ -0,0 +1,134 @@
|
||||
//go:build windows
|
||||
|
||||
package peercreds
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Get returns peer creds for the client connected to this server-side pipe
|
||||
// connection. The conn must be a net.Conn returned from go-winio's ListenPipe.
|
||||
func Get(conn net.Conn) (*Creds, error) {
|
||||
if conn == nil {
|
||||
return nil, ErrUnsupportedConnType
|
||||
}
|
||||
|
||||
h, err := winioPipeHandle(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get client PID for this pipe instance.
|
||||
var pid uint32
|
||||
if err := windows.GetNamedPipeClientProcessId(h, &pid); err != nil {
|
||||
return nil, fmt.Errorf("GetNamedPipeClientProcessId: %w", err)
|
||||
}
|
||||
if pid == 0 {
|
||||
return nil, fmt.Errorf("GetNamedPipeClientProcessId returned pid=0")
|
||||
}
|
||||
|
||||
// Open the client process with query rights.
|
||||
const processQueryLimitedInfo = windows.PROCESS_QUERY_LIMITED_INFORMATION
|
||||
ph, err := windows.OpenProcess(processQueryLimitedInfo, false, pid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("OpenProcess(%d): %w", pid, err)
|
||||
}
|
||||
defer windows.CloseHandle(ph)
|
||||
|
||||
// Open the process token.
|
||||
var token windows.Token
|
||||
if err := windows.OpenProcessToken(ph, windows.TOKEN_QUERY, &token); err != nil {
|
||||
return nil, fmt.Errorf("OpenProcessToken: %w", err)
|
||||
}
|
||||
defer token.Close()
|
||||
|
||||
// Get the token's user SID.
|
||||
tu, err := token.GetTokenUser()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetTokenUser: %w", err)
|
||||
}
|
||||
|
||||
return &Creds{
|
||||
uid: tu.User.Sid.String(),
|
||||
pid: int(pid),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// winioPipeHandle digs the underlying syscall HANDLE out of a go-winio
|
||||
// pipe connection using reflect + unsafe. This depends on the current
|
||||
// internal layout of github.com/Microsoft/go-winio:
|
||||
//
|
||||
// type win32Pipe struct {
|
||||
// *win32File
|
||||
// path string
|
||||
// }
|
||||
//
|
||||
// type win32MessageBytePipe struct {
|
||||
// win32Pipe
|
||||
// writeClosed bool
|
||||
// readEOF bool
|
||||
// }
|
||||
//
|
||||
// type win32File struct {
|
||||
// handle syscall.Handle
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// See pipe.go + file.go in go-winio. :contentReference[oaicite:1]{index=1}
|
||||
func winioPipeHandle(conn net.Conn) (windows.Handle, error) {
|
||||
v := reflect.ValueOf(conn)
|
||||
if !v.IsValid() {
|
||||
return 0, ErrUnsupportedConnType
|
||||
}
|
||||
|
||||
// Peel off interface & pointer layers: net.Conn is an interface and the
|
||||
// concrete type is *win32Pipe or *win32MessageBytePipe.
|
||||
for v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return 0, ErrUnsupportedConnType
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Struct {
|
||||
return 0, ErrUnsupportedConnType
|
||||
}
|
||||
|
||||
var wfField reflect.Value
|
||||
|
||||
// Case 1: *win32Pipe { *win32File; path string }
|
||||
if f := v.FieldByName("win32File"); f.IsValid() && f.Kind() == reflect.Ptr {
|
||||
wfField = f
|
||||
} else if v.NumField() > 0 {
|
||||
// Case 2: *win32MessageBytePipe { win32Pipe; ... }
|
||||
embedded := v.Field(0)
|
||||
if embedded.IsValid() && embedded.Kind() == reflect.Struct {
|
||||
if f2 := embedded.FieldByName("win32File"); f2.IsValid() && f2.Kind() == reflect.Ptr {
|
||||
wfField = f2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !wfField.IsValid() || wfField.IsNil() {
|
||||
return 0, ErrUnsupportedConnType
|
||||
}
|
||||
|
||||
// wfField is a *win32File. Its first field is "handle syscall.Handle".
|
||||
// We only need the first field, so we define a 1-field header type with
|
||||
// compatible layout and reinterpret the pointer.
|
||||
type win32FileHeader struct {
|
||||
Handle windows.Handle // same underlying type as syscall.Handle
|
||||
}
|
||||
|
||||
ptr := unsafe.Pointer(wfField.Pointer())
|
||||
h := (*win32FileHeader)(ptr).Handle
|
||||
if h == 0 {
|
||||
return 0, fmt.Errorf("winio pipe handle is 0")
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -51,7 +53,12 @@ func run(ctx context.Context, opts ...service.Option) {
|
||||
)
|
||||
defer p.Shutdown(ctx)
|
||||
|
||||
address := "0.0.0.0:9991"
|
||||
// address := "0.0.0.0:9991"
|
||||
address := "unix:///tmp/example.sock"
|
||||
if runtime.GOOS == "windows" {
|
||||
address = `\\.\pipe\example`
|
||||
}
|
||||
defer os.Remove("/tmp/example.sock")
|
||||
|
||||
var svc service.Service
|
||||
opts = append(opts,
|
||||
@@ -96,7 +103,7 @@ func run(ctx context.Context, opts ...service.Option) {
|
||||
copts := []client.Option{
|
||||
// client.WithName(name),
|
||||
// client.WithVersion(version),
|
||||
client.WithAddress("localhost:9991"),
|
||||
client.WithAddress(address),
|
||||
// client.WithRegistry(mdns.NewRegistry()),
|
||||
client.WithSecure(secure),
|
||||
client.WithInterceptors(tracing.NewClientInterceptors()),
|
||||
|
||||
@@ -32,6 +32,7 @@ require (
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bombsimon/logrusr/v4 v4.1.0 // indirect
|
||||
github.com/bufbuild/protocompile v0.14.1 // indirect
|
||||
@@ -63,6 +64,7 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect
|
||||
github.com/traefik/grpc-web v0.16.0 // indirect
|
||||
github.com/uptrace/opentelemetry-go-extra/otellogrus v0.3.2 // indirect
|
||||
|
||||
@@ -35,6 +35,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
@@ -326,6 +328,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA=
|
||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
|
||||
github.com/traefik/grpc-web v0.16.0 h1:eeUWZaFg6ZU0I9dWOYE2D5qkNzRBmXzzuRlxdltascY=
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/peer"
|
||||
|
||||
"go.linka.cloud/grpc-tookit/example/pb"
|
||||
"go.linka.cloud/grpc-toolkit/interceptors/iface"
|
||||
@@ -30,6 +31,11 @@ func (g *GreeterHandler) SayHello(ctx context.Context, req *pb.HelloRequest) (*p
|
||||
span := trace.SpanFromContext(ctx)
|
||||
span.SetAttributes(attribute.String("name", req.Name))
|
||||
logger.C(ctx).Infof("replying to %s", req.Name)
|
||||
if p, ok := peer.FromContext(ctx); ok {
|
||||
logger.C(ctx).Infof("peer auth info: %+v", p.AuthInfo)
|
||||
} else {
|
||||
logger.C(ctx).Infof("no peer info")
|
||||
}
|
||||
return &pb.HelloReply{Message: hello(req.Name)}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,15 +27,12 @@ func newService(ctx context.Context, opts ...service.Option) (service.Service, e
|
||||
log := logger.C(ctx)
|
||||
metrics := metrics2.NewInterceptors(metrics2.WithExemplarFromContext(metrics2.DefaultExemplarFromCtx))
|
||||
|
||||
address := "0.0.0.0:9991"
|
||||
|
||||
var svc service.Service
|
||||
opts = append(opts,
|
||||
service.WithContext(ctx),
|
||||
service.WithAddress(address),
|
||||
// service.WithRegistry(mdns.NewRegistry()),
|
||||
service.WithReflection(true),
|
||||
service.WithoutCmux(),
|
||||
// service.WithoutCmux(),
|
||||
service.WithGateway(pb.RegisterGreeterHandler),
|
||||
service.WithGatewayPrefix("/rest"),
|
||||
service.WithGRPCWeb(true),
|
||||
|
||||
3
go.mod
3
go.mod
@@ -5,6 +5,7 @@ go 1.23.0
|
||||
toolchain go1.24.3
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.2
|
||||
github.com/alta/protopatch v0.5.3
|
||||
github.com/bombsimon/logrusr/v4 v4.0.0
|
||||
github.com/caitlinelfring/go-env-default v1.1.0
|
||||
@@ -56,6 +57,7 @@ require (
|
||||
go.uber.org/multierr v1.7.0
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/sync v0.14.0
|
||||
golang.org/x/sys v0.33.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237
|
||||
google.golang.org/grpc v1.72.1
|
||||
@@ -96,7 +98,6 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@@ -53,6 +53,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
|
||||
11
service/listen.go
Normal file
11
service/listen.go
Normal file
@@ -0,0 +1,11 @@
|
||||
//go:build !windows
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func listen(network, address string) (net.Listener, error) {
|
||||
return net.Listen(network, address)
|
||||
}
|
||||
14
service/listen_windows.go
Normal file
14
service/listen_windows.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
)
|
||||
|
||||
func listen(network, address string) (net.Listener, error) {
|
||||
if network == "pipe" {
|
||||
return winio.ListenPipe(address, nil)
|
||||
}
|
||||
return net.Listen(network, address)
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func newService(opts ...Option) (*service, error) {
|
||||
grpc.StreamInterceptor(si),
|
||||
grpc.UnaryInterceptor(ui),
|
||||
}
|
||||
if _, ok := s.opts.lis.(*net.UnixListener); ok || strings.HasPrefix(s.opts.address, "unix://") {
|
||||
if _, ok := s.opts.lis.(*net.UnixListener); ok || strings.HasPrefix(s.opts.address, "unix://") || strings.HasPrefix(s.opts.address, `\\.\pipe\`) {
|
||||
gopts = append(gopts, grpc.Creds(peercreds.New()))
|
||||
}
|
||||
s.server = grpc.NewServer(append(gopts, s.opts.serverOpts...)...)
|
||||
@@ -179,9 +179,12 @@ func (s *service) start() (*errgroup.Group, error) {
|
||||
network = "unix"
|
||||
s.opts.address = strings.TrimPrefix(s.opts.address, "unix://")
|
||||
}
|
||||
if strings.HasPrefix(s.opts.address, `\\.\pipe\`) {
|
||||
network = "pipe"
|
||||
}
|
||||
|
||||
if s.opts.lis == nil {
|
||||
lis, err := net.Listen(network, s.opts.address)
|
||||
lis, err := listen(network, s.opts.address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user