Skip to content

Commit

Permalink
internal: move syscall.Conn wrapper into a separate package (#2457)
Browse files Browse the repository at this point in the history
Also skip wrapping if `rawConn` doesn't implement `syscall.Conn`.
  • Loading branch information
menghanl authored Nov 15, 2018
1 parent 0fccf8b commit ef2b8e2
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 27 deletions.
19 changes: 3 additions & 16 deletions credentials/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"strings"

"github.com/golang/protobuf/proto"
"google.golang.org/grpc/credentials/internal"
)

// alpnProtoStr are the specified application level protocols for gRPC.
Expand Down Expand Up @@ -187,15 +188,15 @@ func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawCon
case <-ctx.Done():
return nil, nil, ctx.Err()
}
return tlsConn{Conn: conn, rawConn: rawConn}, TLSInfo{conn.ConnectionState()}, nil
return internal.WrapSyscallConn(rawConn, conn), TLSInfo{conn.ConnectionState()}, nil
}

func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) {
conn := tls.Server(rawConn, c.config)
if err := conn.Handshake(); err != nil {
return nil, nil, err
}
return tlsConn{Conn: conn, rawConn: rawConn}, TLSInfo{conn.ConnectionState()}, nil
return internal.WrapSyscallConn(rawConn, conn), TLSInfo{conn.ConnectionState()}, nil
}

func (c *tlsCreds) Clone() TransportCredentials {
Expand Down Expand Up @@ -285,20 +286,6 @@ type OtherChannelzSecurityValue struct {

func (*OtherChannelzSecurityValue) isChannelzSecurityValue() {}

// tlsConn keeps reference of rawConn to support syscall.Conn for channelz.
// SyscallConn() (the method in interface syscall.Conn) is explicitly
// implemented on this type,
//
// Interface syscall.Conn is implemented by most net.Conn implementations (e.g.
// TCPConn, UnixConn), but is not part of net.Conn interface. So wrapper conns
// that embed net.Conn don't implement syscall.Conn. (Side note: tls.Conn
// doesn't embed net.Conn, so even if syscall.Conn is part of net.Conn, it won't
// help here).
type tlsConn struct {
*tls.Conn
rawConn net.Conn
}

var cipherSuiteLookup = map[uint16]string{
tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA",
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
Expand Down
61 changes: 61 additions & 0 deletions credentials/internal/syscallconn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// +build !appengine

/*
*
* Copyright 2018 gRPC 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.
*
*/

// Package internal contains credentials-internal code.
package internal

import (
"net"
"syscall"
)

type sysConn = syscall.Conn

// syscallConn keeps reference of rawConn to support syscall.Conn for channelz.
// SyscallConn() (the method in interface syscall.Conn) is explicitly
// implemented on this type,
//
// Interface syscall.Conn is implemented by most net.Conn implementations (e.g.
// TCPConn, UnixConn), but is not part of net.Conn interface. So wrapper conns
// that embed net.Conn don't implement syscall.Conn. (Side note: tls.Conn
// doesn't embed net.Conn, so even if syscall.Conn is part of net.Conn, it won't
// help here).
type syscallConn struct {
net.Conn
// sysConn is a type alias of syscall.Conn. It's necessary because the name
// `Conn` collides with `net.Conn`.
sysConn
}

// WrapSyscallConn tries to wrap rawConn and newConn into a net.Conn that
// implements syscall.Conn. rawConn will be used to support syscall, and newConn
// will be used for read/write.
//
// This function returns newConn if rawConn doesn't implement syscall.Conn.
func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn {
sysConn, ok := rawConn.(syscall.Conn)
if !ok {
return newConn
}
return &syscallConn{
Conn: newConn,
sysConn: sysConn,
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build !appengine
// +build appengine

/*
*
Expand All @@ -18,18 +18,13 @@
*
*/

package credentials
package internal

import (
"errors"
"syscall"
"net"
)

// implements the syscall.Conn interface
func (c tlsConn) SyscallConn() (syscall.RawConn, error) {
conn, ok := c.rawConn.(syscall.Conn)
if !ok {
return nil, errors.New("RawConn does not implement syscall.Conn")
}
return conn.SyscallConn()
// WrapSyscallConn returns newConn on appengine.
func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn {
return newConn
}
64 changes: 64 additions & 0 deletions credentials/internal/syscallconn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// +build !appengine

/*
*
* Copyright 2018 gRPC 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.
*
*/

package internal_test

import (
"net"
"syscall"
"testing"

"google.golang.org/grpc/credentials/internal"
)

type syscallConn struct {
net.Conn
}

func (*syscallConn) SyscallConn() (syscall.RawConn, error) {
return nil, nil
}

type nonSyscallConn struct {
net.Conn
}

func TestWrapSyscallConn(t *testing.T) {
sc := &syscallConn{}
nsc := &nonSyscallConn{}

wrapConn := internal.WrapSyscallConn(sc, nsc)
if _, ok := wrapConn.(syscall.Conn); !ok {
t.Errorf("returned conn (type %T) doesn't implement syscall.Conn, want implement", wrapConn)
}
}

func TestWrapSyscallConnNoWrap(t *testing.T) {
nscRaw := &nonSyscallConn{}
nsc := &nonSyscallConn{}

wrapConn := internal.WrapSyscallConn(nscRaw, nsc)
if _, ok := wrapConn.(syscall.Conn); ok {
t.Errorf("returned conn (type %T) implements syscall.Conn, want not implement", wrapConn)
}
if wrapConn != nsc {
t.Errorf("returned conn is %p, want %p (the passed-in newConn)", wrapConn, nsc)
}
}

0 comments on commit ef2b8e2

Please sign in to comment.