[full-ci] revaBump-2.37.0 (#1433)

* revaBump-2.37.0

* Pipeline Restart, empty change

---------

Co-authored-by: Michael 'Flimmy' Flemming <m.flemming@opencloud.eu>
This commit is contained in:
Viktor Scharf
2025-09-02 09:29:50 +02:00
committed by GitHub
co-authored by Michael 'Flimmy' Flemming
parent a637ba34b1
commit 6352068a66
58 changed files with 12132 additions and 221 deletions
+1
View File
@@ -0,0 +1 @@
1.24.1
+10
View File
@@ -1,3 +1,13 @@
## v1.7.0
CHANGES:
* When go-plugin encounters a stack trace on the server stderr stream, it now raises output to a log-level of Error instead of Debug. [[GH-292](https://github.com/hashicorp/go-plugin/pull/292)]
ENHANCEMENTS:
* Don't spend resources parsing log lines when logging is disabled [[GH-352](https://github.com/hashicorp/go-plugin/pull/352)]
## v1.6.2
ENHANCEMENTS:
+60 -24
View File
@@ -14,7 +14,6 @@ import (
"fmt"
"hash"
"io"
"io/ioutil"
"net"
"os"
"os/exec"
@@ -202,7 +201,7 @@ type ClientConfig struct {
// SyncStdout, SyncStderr can be set to override the
// respective os.Std* values in the plugin. Care should be taken to
// avoid races here. If these are nil, then this will be set to
// ioutil.Discard.
// io.Discard.
SyncStdout io.Writer
SyncStderr io.Writer
@@ -345,7 +344,7 @@ func (s *SecureConfig) Check(filePath string) (bool, error) {
if err != nil {
return false, err
}
defer file.Close()
defer func() { _ = file.Close() }()
_, err = io.Copy(s.Hash, file)
if err != nil {
@@ -401,7 +400,7 @@ func NewClient(config *ClientConfig) (c *Client) {
}
if config.Stderr == nil {
config.Stderr = ioutil.Discard
config.Stderr = io.Discard
}
if config.SyncStdout == nil {
@@ -514,7 +513,7 @@ func (c *Client) Kill() {
c.clientWaitGroup.Wait()
if hostSocketDir != "" {
os.RemoveAll(hostSocketDir)
_ = os.RemoveAll(hostSocketDir)
}
// Make sure there is no reference to the old process after it has been
@@ -743,7 +742,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
rErr := recover()
if err != nil || rErr != nil {
runner.Kill(context.Background())
_ = runner.Kill(context.Background())
}
if rErr != nil {
@@ -780,7 +779,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
c.logger.Info("plugin process exited", "plugin", runner.Name(), "id", runner.ID())
}
os.Stderr.Sync()
_ = os.Stderr.Sync()
// Set that we exited, which takes a lock
c.l.Lock()
@@ -853,15 +852,15 @@ func (c *Client) Start() (addr net.Addr, err error) {
var coreProtocol int
coreProtocol, err = strconv.Atoi(parts[0])
if err != nil {
err = fmt.Errorf("Error parsing core protocol version: %s", err)
err = fmt.Errorf("error parsing core protocol version: %s", err)
return
}
if coreProtocol != CoreProtocolVersion {
err = fmt.Errorf("Incompatible core API version with plugin. "+
err = fmt.Errorf("incompatible core API version with plugin. "+
"Plugin version: %s, Core version: %d\n\n"+
"To fix this, the plugin usually only needs to be recompiled.\n"+
"Please report this to the plugin author.", parts[0], CoreProtocolVersion)
"Please report this to the plugin author", parts[0], CoreProtocolVersion)
return
}
}
@@ -887,10 +886,16 @@ func (c *Client) Start() (addr net.Addr, err error) {
switch network {
case "tcp":
addr, err = net.ResolveTCPAddr("tcp", address)
if err != nil {
return nil, err
}
case "unix":
addr, err = net.ResolveUnixAddr("unix", address)
if err != nil {
return nil, err
}
default:
err = fmt.Errorf("Unknown address type: %s", address)
return nil, fmt.Errorf("unknown address type: %s", address)
}
// If we have a server type, then record that. We default to net/rpc
@@ -908,7 +913,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
}
}
if !found {
err = fmt.Errorf("Unsupported plugin protocol %q. Supported: %v",
err = fmt.Errorf("unsupported plugin protocol %q. Supported: %v",
c.protocol, c.config.AllowedProtocols)
return addr, err
}
@@ -986,7 +991,7 @@ func (c *Client) reattach() (net.Addr, error) {
defer c.ctxCancel()
// Wait for the process to die
r.Wait(context.Background())
_ = r.Wait(context.Background())
// Log so we can see it
c.logger.Debug("reattached plugin process exited")
@@ -1041,7 +1046,7 @@ func (c *Client) checkProtoVersion(protoVersion string) (int, PluginSet, error)
return version, plugins, nil
}
return 0, nil, fmt.Errorf("Incompatible API version with plugin. "+
return 0, nil, fmt.Errorf("incompatible API version with plugin. "+
"Plugin version: %d, Client versions: %d", serverVersion, clientVersions)
}
@@ -1097,8 +1102,8 @@ func (c *Client) Protocol() Protocol {
return c.protocol
}
func netAddrDialer(addr net.Addr) func(string, time.Duration) (net.Conn, error) {
return func(_ string, _ time.Duration) (net.Conn, error) {
func netAddrDialer(addr net.Addr) func(context.Context, string) (net.Conn, error) {
return func(context.Context, string) (net.Conn, error) {
// Connect to the client
conn, err := net.Dial(addr.Network(), addr.String())
if err != nil {
@@ -1106,7 +1111,7 @@ func netAddrDialer(addr net.Addr) func(string, time.Duration) (net.Conn, error)
}
if tcpConn, ok := conn.(*net.TCPConn); ok {
// Make sure to set keep alive so that the connection doesn't die
tcpConn.SetKeepAlive(true)
_ = tcpConn.SetKeepAlive(true)
}
return conn, nil
@@ -1115,7 +1120,7 @@ func netAddrDialer(addr net.Addr) func(string, time.Duration) (net.Conn, error)
// dialer is compatible with grpc.WithDialer and creates the connection
// to the plugin.
func (c *Client) dialer(_ string, timeout time.Duration) (net.Conn, error) {
func (c *Client) dialer(ctx context.Context, _ string) (net.Conn, error) {
muxer, err := c.getGRPCMuxer(c.address)
if err != nil {
return nil, err
@@ -1128,7 +1133,7 @@ func (c *Client) dialer(_ string, timeout time.Duration) (net.Conn, error) {
return nil, err
}
} else {
conn, err = netAddrDialer(c.address)("", timeout)
conn, err = netAddrDialer(c.address)(ctx, "")
if err != nil {
return nil, err
}
@@ -1162,13 +1167,21 @@ func (c *Client) getGRPCMuxer(addr net.Addr) (*grpcmux.GRPCClientMuxer, error) {
func (c *Client) logStderr(name string, r io.Reader) {
defer c.clientWaitGroup.Done()
defer c.pipesWaitGroup.Done()
l := c.logger.Named(filepath.Base(name))
loggerLevel := l.GetLevel()
loggerDisabled := loggerLevel == hclog.Off
reader := bufio.NewReaderSize(r, c.config.PluginLogBufferSize)
// continuation indicates the previous line was a prefix
continuation := false
// inPanic indicates we saw the start of a stack trace and should divert all
// remaining untagged lines to stderr
var inPanic bool
for {
line, isPrefix, err := reader.ReadLine()
switch {
case err == io.EOF:
@@ -1178,7 +1191,7 @@ func (c *Client) logStderr(name string, r io.Reader) {
return
}
c.config.Stderr.Write(line)
_, _ = c.config.Stderr.Write(line)
// The line was longer than our max token size, so it's likely
// incomplete and won't unmarshal.
@@ -1187,14 +1200,26 @@ func (c *Client) logStderr(name string, r io.Reader) {
// if we're finishing a continued line, add the newline back in
if !isPrefix {
c.config.Stderr.Write([]byte{'\n'})
_, _ = c.config.Stderr.Write([]byte{'\n'})
}
continuation = isPrefix
continue
}
c.config.Stderr.Write([]byte{'\n'})
_, _ = c.config.Stderr.Write([]byte{'\n'})
//
// Any side-effects other than writing to the hclog logger must be
// above this point!
//
if loggerDisabled {
// If the logger we'd be writing to is completely disabled then
// we can skip all of the parsing work to decide what log level
// we'd use to write this line.
continue
}
entry, err := parseJSON(line)
// If output is not JSON format, print directly to Debug
@@ -1212,14 +1237,25 @@ func (c *Client) logStderr(name string, r io.Reader) {
l.Warn(line)
case strings.HasPrefix(line, "[ERROR]"):
l.Error(line)
case strings.HasPrefix(line, "panic: ") || strings.HasPrefix(line, "fatal error: "):
inPanic = true
fallthrough
case inPanic:
l.Error(line)
default:
l.Debug(line)
}
} else {
out := flattenKVPairs(entry.KVPairs)
logLevel := hclog.LevelFromString(entry.Level)
if logLevel != hclog.NoLevel && logLevel < loggerLevel {
// The logger will ignore this log entry anyway, so we
// won't spend any more time preparing it.
continue
}
out := flattenKVPairs(entry.KVPairs)
out = append(out, "timestamp", entry.Timestamp.Format(hclog.TimeFormat))
switch hclog.LevelFromString(entry.Level) {
switch logLevel {
case hclog.Trace:
l.Trace(entry.Message, out...)
case hclog.Debug:
+5 -9
View File
@@ -100,8 +100,6 @@ func (s *gRPCBrokerServer) StartStream(stream plugin.GRPCBroker_StartStreamServe
case s.recv <- i:
}
}
return nil
}
// Send is used by the GRPCBroker to pass connection information into the stream
@@ -210,8 +208,6 @@ func (s *gRPCBrokerClientImpl) StartStream() error {
case s.recv <- i:
}
}
return nil
}
// Send is used by the GRPCBroker to pass connection information into the stream
@@ -382,7 +378,7 @@ func (b *GRPCBroker) AcceptAndServe(id uint32, newGRPCServer func([]grpc.ServerO
log.Printf("[ERR] plugin: plugin acceptAndServe error: %s", err)
return
}
defer ln.Close()
defer func() { _ = ln.Close() }()
var opts []grpc.ServerOption
if b.tls != nil {
@@ -418,7 +414,7 @@ func (b *GRPCBroker) AcceptAndServe(id uint32, newGRPCServer func([]grpc.ServerO
}
// Block until we are done
g.Run()
_ = g.Run()
}
// Close closes the stream and all servers.
@@ -502,8 +498,8 @@ func (b *GRPCBroker) knock(id uint32) error {
return nil
}
func (b *GRPCBroker) muxDial(id uint32) func(string, time.Duration) (net.Conn, error) {
return func(string, time.Duration) (net.Conn, error) {
func (b *GRPCBroker) muxDial(id uint32) func(context.Context, string) (net.Conn, error) {
return func(context.Context, string) (net.Conn, error) {
b.dialMutex.Lock()
defer b.dialMutex.Unlock()
@@ -557,7 +553,7 @@ func (b *GRPCBroker) DialWithOptions(id uint32, opts ...grpc.DialOption) (conn *
case "unix":
addr, err = net.ResolveUnixAddr("unix", address)
default:
err = fmt.Errorf("Unknown address type: %s", c.Address)
err = fmt.Errorf("unknown address type: %s", c.Address)
}
if err != nil {
return nil, err
+7 -7
View File
@@ -9,20 +9,20 @@ import (
"fmt"
"math"
"net"
"time"
"github.com/hashicorp/go-plugin/internal/plugin"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/health/grpc_health_v1"
)
func dialGRPCConn(tls *tls.Config, dialer func(string, time.Duration) (net.Conn, error), dialOpts ...grpc.DialOption) (*grpc.ClientConn, error) {
func dialGRPCConn(tls *tls.Config, dialer func(context.Context, string) (net.Conn, error), dialOpts ...grpc.DialOption) (*grpc.ClientConn, error) {
// Build dialing options.
opts := make([]grpc.DialOption, 0)
// We use a custom dialer so that we can connect over unix domain sockets.
opts = append(opts, grpc.WithDialer(dialer))
opts = append(opts, grpc.WithContextDialer(dialer))
// Fail right away
opts = append(opts, grpc.FailOnNonTempDialError(true))
@@ -30,7 +30,7 @@ func dialGRPCConn(tls *tls.Config, dialer func(string, time.Duration) (net.Conn,
// If we have no TLS configuration set, we need to explicitly tell grpc
// that we're connecting with an insecure connection.
if tls == nil {
opts = append(opts, grpc.WithInsecure())
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
} else {
opts = append(opts, grpc.WithTransportCredentials(
credentials.NewTLS(tls)))
@@ -70,7 +70,7 @@ func newGRPCClient(doneCtx context.Context, c *Client) (*GRPCClient, error) {
brokerGRPCClient := newGRPCBrokerClient(conn)
broker := newGRPCBroker(brokerGRPCClient, c.config.TLSConfig, c.unixSocketCfg, c.runner, muxer)
go broker.Run()
go brokerGRPCClient.StartStream()
go func() { _ = brokerGRPCClient.StartStream() }()
// Start the stdio client
stdioClient, err := newGRPCStdioClient(doneCtx, c.logger.Named("stdio"), conn)
@@ -103,8 +103,8 @@ type GRPCClient struct {
// ClientProtocol impl.
func (c *GRPCClient) Close() error {
c.broker.Close()
c.controller.Shutdown(c.doneCtx, &plugin.Empty{})
_ = c.broker.Close()
_, _ = c.controller.Shutdown(c.doneCtx, &plugin.Empty{})
return c.Conn.Close()
}
+2 -2
View File
@@ -119,7 +119,7 @@ func (s *GRPCServer) Stop() {
s.server.Stop()
if s.broker != nil {
s.broker.Close()
_ = s.broker.Close()
s.broker = nil
}
}
@@ -130,7 +130,7 @@ func (s *GRPCServer) GracefulStop() {
s.server.GracefulStop()
if s.broker != nil {
s.broker.Close()
_ = s.broker.Close()
s.broker = nil
}
}
+1 -1
View File
@@ -178,7 +178,7 @@ func copyChan(log hclog.Logger, dst chan<- []byte, src io.Reader) {
for {
// Make our data buffer. We allocate a new one per loop iteration
// so that we can send it over the channel.
var data [1024]byte
var data [grpcStdioBuffer]byte
// Read the data, this will block until data is available
n, err := bufsrc.Read(data[:])
+1 -1
View File
@@ -30,7 +30,7 @@ func ReattachFunc(pid int, addr net.Addr) runner.ReattachFunc {
if err != nil {
return nil, ErrProcessNotFound
}
conn.Close()
_ = conn.Close()
return &CmdAttachedRunner{
pid: pid,
+1 -1
View File
@@ -20,7 +20,7 @@ var (
// ErrProcessNotFound is returned when a client is instantiated to
// reattach to an existing process and it isn't found.
ErrProcessNotFound = errors.New("Reattachment process not found")
ErrProcessNotFound = errors.New("reattachment process not found")
)
const unrecognizedRemotePluginMessage = `This usually means
+3 -3
View File
@@ -53,13 +53,13 @@ func additionalNotesAboutCommand(path string) string {
}
if elfFile, err := elf.Open(path); err == nil {
defer elfFile.Close()
defer func() { _ = elfFile.Close() }()
notes += fmt.Sprintf(" ELF architecture: %s (current architecture: %s)\n", elfFile.Machine, runtime.GOARCH)
} else if machoFile, err := macho.Open(path); err == nil {
defer machoFile.Close()
defer func() { _ = machoFile.Close() }()
notes += fmt.Sprintf(" MachO architecture: %s (current architecture: %s)\n", machoFile.Cpu, runtime.GOARCH)
} else if peFile, err := pe.Open(path); err == nil {
defer peFile.Close()
defer func() { _ = peFile.Close() }()
machine, ok := peTypes[peFile.Machine]
if !ok {
machine = "unknown"
+6 -6
View File
@@ -10,10 +10,10 @@ import (
// logEntry is the JSON payload that gets sent to Stderr from the plugin to the host
type logEntry struct {
Message string `json:"@message"`
Level string `json:"@level"`
Timestamp time.Time `json:"timestamp"`
KVPairs []*logEntryKV `json:"kv_pairs"`
Message string `json:"@message"`
Level string `json:"@level"`
Timestamp time.Time `json:"timestamp"`
KVPairs []logEntryKV `json:"kv_pairs"`
}
// logEntryKV is a key value pair within the Output payload
@@ -24,7 +24,7 @@ type logEntryKV struct {
// flattenKVPairs is used to flatten KVPair slice into []interface{}
// for hclog consumption.
func flattenKVPairs(kvs []*logEntryKV) []interface{} {
func flattenKVPairs(kvs []logEntryKV) []interface{} {
var result []interface{}
for _, kv := range kvs {
result = append(result, kv.Key)
@@ -66,7 +66,7 @@ func parseJSON(input []byte) (*logEntry, error) {
// Parse dynamic KV args from the hclog payload.
for k, v := range raw {
entry.KVPairs = append(entry.KVPairs, &logEntryKV{
entry.KVPairs = append(entry.KVPairs, logEntryKV{
Key: k,
Value: v,
})
+7 -9
View File
@@ -68,7 +68,7 @@ func (m *MuxBroker) Accept(id uint32) (net.Conn, error) {
// Ack our connection
if err := binary.Write(c, binary.LittleEndian, id); err != nil {
c.Close()
_ = c.Close()
return nil, err
}
@@ -105,18 +105,18 @@ func (m *MuxBroker) Dial(id uint32) (net.Conn, error) {
// Write the stream ID onto the wire.
if err := binary.Write(stream, binary.LittleEndian, id); err != nil {
stream.Close()
_ = stream.Close()
return nil, err
}
// Read the ack that we connected. Then we're off!
var ack uint32
if err := binary.Read(stream, binary.LittleEndian, &ack); err != nil {
stream.Close()
_ = stream.Close()
return nil, err
}
if ack != id {
stream.Close()
_ = stream.Close()
return nil, fmt.Errorf("bad ack: %d (expected %d)", ack, id)
}
@@ -148,7 +148,7 @@ func (m *MuxBroker) Run() {
// Read the stream ID from the stream
var id uint32
if err := binary.Read(stream, binary.LittleEndian, &id); err != nil {
stream.Close()
_ = stream.Close()
continue
}
@@ -199,9 +199,7 @@ func (m *MuxBroker) timeoutWait(id uint32, p *muxBrokerPending) {
// If we timed out, then check if we have a channel in the buffer,
// and if so, close it.
if timeout {
select {
case s := <-p.ch:
s.Close()
}
s := <-p.ch
_ = s.Close()
}
}
+7 -7
View File
@@ -33,7 +33,7 @@ func newRPCClient(c *Client) (*RPCClient, error) {
}
if tcpConn, ok := conn.(*net.TCPConn); ok {
// Make sure to set keep alive so that the connection doesn't die
tcpConn.SetKeepAlive(true)
_ = tcpConn.SetKeepAlive(true)
}
if c.config.TLSConfig != nil {
@@ -43,7 +43,7 @@ func newRPCClient(c *Client) (*RPCClient, error) {
// Create the actual RPC client
result, err := NewRPCClient(conn, c.config.Plugins)
if err != nil {
conn.Close()
_ = conn.Close()
return nil, err
}
@@ -52,7 +52,7 @@ func newRPCClient(c *Client) (*RPCClient, error) {
c.config.SyncStdout,
c.config.SyncStderr)
if err != nil {
result.Close()
_ = result.Close()
return nil, err
}
@@ -65,23 +65,23 @@ func NewRPCClient(conn io.ReadWriteCloser, plugins map[string]Plugin) (*RPCClien
// Create the yamux client so we can multiplex
mux, err := yamux.Client(conn, nil)
if err != nil {
conn.Close()
_ = conn.Close()
return nil, err
}
// Connect to the control stream.
control, err := mux.Open()
if err != nil {
mux.Close()
_ = mux.Close()
return nil, err
}
// Connect stdout, stderr streams
stdstream := make([]net.Conn, 2)
for i, _ := range stdstream {
for i := range stdstream {
stdstream[i], err = mux.Open()
if err != nil {
mux.Close()
_ = mux.Close()
return nil, err
}
}
+5 -5
View File
@@ -69,7 +69,7 @@ func (s *RPCServer) ServeConn(conn io.ReadWriteCloser) {
// First create the yamux server to wrap this connection
mux, err := yamux.Server(conn, nil)
if err != nil {
conn.Close()
_ = conn.Close()
log.Printf("[ERR] plugin: error creating yamux server: %s", err)
return
}
@@ -77,7 +77,7 @@ func (s *RPCServer) ServeConn(conn io.ReadWriteCloser) {
// Accept the control connection
control, err := mux.Accept()
if err != nil {
mux.Close()
_ = mux.Close()
if err != io.EOF {
log.Printf("[ERR] plugin: error accepting control connection: %s", err)
}
@@ -90,7 +90,7 @@ func (s *RPCServer) ServeConn(conn io.ReadWriteCloser) {
for i := range stdstream {
stdstream[i], err = mux.Accept()
if err != nil {
mux.Close()
_ = mux.Close()
log.Printf("[ERR] plugin: accepting stream %d: %s", i, err)
return
}
@@ -107,10 +107,10 @@ func (s *RPCServer) ServeConn(conn io.ReadWriteCloser) {
// Use the control connection to build the dispenser and serve the
// connection.
server := rpc.NewServer()
server.RegisterName("Control", &controlServer{
_ = server.RegisterName("Control", &controlServer{
server: s,
})
server.RegisterName("Dispenser", &dispenseServer{
_ = server.RegisterName("Dispenser", &dispenseServer{
broker: broker,
plugins: s.Plugins,
})
+6 -6
View File
@@ -290,7 +290,7 @@ func Serve(opts *ServeConfig) {
// Close the listener on return. We wrap this in a func() on purpose
// because the "listener" reference may change to TLS.
defer func() {
listener.Close()
_ = listener.Close()
}()
var tlsConfig *tls.Config
@@ -443,7 +443,7 @@ func Serve(opts *ServeConfig) {
protocolLine += fmt.Sprintf("|%v", grpcBrokerMultiplexingSupported)
}
fmt.Printf("%s\n", protocolLine)
os.Stdout.Sync()
_ = os.Stdout.Sync()
} else if ch := opts.Test.ReattachConfigCh; ch != nil {
// Send back the reattach config that can be used. This isn't
// quite ready if they connect immediately but the client should
@@ -505,7 +505,7 @@ func Serve(opts *ServeConfig) {
// Cancellation. We can stop the server by closing the listener.
// This isn't graceful at all but this is currently only used by
// tests and its our only way to stop.
listener.Close()
_ = listener.Close()
// If this is a grpc server, then we also ask the server itself to
// end which will kill all connections. There isn't an easy way to do
@@ -546,7 +546,7 @@ func serverListener_tcp() (net.Listener, error) {
default:
minPort, err = strconv.ParseInt(envMinPort, 10, 32)
if err != nil {
return nil, fmt.Errorf("Couldn't get value from PLUGIN_MIN_PORT: %v", err)
return nil, fmt.Errorf("couldn't get value from PLUGIN_MIN_PORT: %v", err)
}
}
@@ -556,7 +556,7 @@ func serverListener_tcp() (net.Listener, error) {
default:
maxPort, err = strconv.ParseInt(envMaxPort, 10, 32)
if err != nil {
return nil, fmt.Errorf("Couldn't get value from PLUGIN_MAX_PORT: %v", err)
return nil, fmt.Errorf("couldn't get value from PLUGIN_MAX_PORT: %v", err)
}
}
@@ -572,7 +572,7 @@ func serverListener_tcp() (net.Listener, error) {
}
}
return nil, errors.New("Couldn't bind plugin TCP listener")
return nil, errors.New("couldn't bind plugin TCP listener")
}
func serverListener_unix(unixSocketCfg UnixSocketConfig) (net.Listener, error) {
+6 -4
View File
@@ -14,6 +14,7 @@ import (
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin/internal/grpcmux"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
// TestOptions allows specifying options that can affect the behavior of the
@@ -46,7 +47,7 @@ func TestConn(t testing.TB) (net.Conn, net.Conn) {
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
defer l.Close()
defer func() { _ = l.Close() }()
var err error
serverConn, err = l.Accept()
if err != nil {
@@ -116,19 +117,20 @@ func TestGRPCConn(t testing.TB, register func(*grpc.Server)) (*grpc.ClientConn,
server := grpc.NewServer()
register(server)
go server.Serve(l)
go func() { _ = server.Serve(l) }()
// Connect to the server
conn, err := grpc.Dial(
l.Addr().String(),
grpc.WithBlock(),
grpc.WithInsecure())
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
t.Fatalf("err: %s", err)
}
// Connection successful, close the listener
l.Close()
_ = l.Close()
return conn, server
}
+2
View File
@@ -1,3 +1,5 @@
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
1. Definitions
+6 -2
View File
@@ -3,7 +3,6 @@ package yamux
import (
"fmt"
"io"
"log"
"os"
"time"
)
@@ -51,7 +50,12 @@ type Config struct {
// Logger is used to pass in the logger to be used. Either Logger or
// LogOutput can be set, not both.
Logger *log.Logger
Logger Logger
}
func (c *Config) Clone() *Config {
c2 := *c
return &c2
}
// DefaultConfig is used to return a default configuration
+19 -2
View File
@@ -3,6 +3,7 @@ package yamux
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
@@ -34,7 +35,7 @@ type Session struct {
config *Config
// logger is used for our logs
logger *log.Logger
logger Logger
// conn is the underlying connection
conn io.ReadWriteCloser
@@ -250,6 +251,22 @@ func (s *Session) AcceptStream() (*Stream, error) {
}
}
// AcceptStream is used to block until the next available stream
// is ready to be accepted.
func (s *Session) AcceptStreamWithContext(ctx context.Context) (*Stream, error) {
select {
case <-ctx.Done():
return nil, ctx.Err()
case stream := <-s.acceptCh:
if err := stream.sendWindowUpdate(); err != nil {
return nil, err
}
return stream, nil
case <-s.shutdownCh:
return nil, s.shutdownErr
}
}
// Close is used to close the session and all streams.
// Attempts to send a GoAway before closing the connection.
func (s *Session) Close() error {
@@ -339,7 +356,7 @@ func (s *Session) Ping() (time.Duration, error) {
}
// Compute the RTT
return time.Now().Sub(start), nil
return time.Since(start), nil
}
// keepalive is a long running goroutine that periodically does
+1 -1
View File
@@ -100,7 +100,7 @@ fire a request without waiting for the RTT of the ACK.
This does introduce the possibility of a connection being rejected
after data has been sent already. This is a slight semantic difference
from TCP, where the conection cannot be refused after it is opened.
from TCP, where the connection cannot be refused after it is opened.
Clients should be prepared to handle this by checking for an error
that indicates a RST was received.
+23 -11
View File
@@ -95,10 +95,12 @@ func (s *Stream) StreamID() uint32 {
func (s *Stream) Read(b []byte) (n int, err error) {
defer asyncNotify(s.recvNotifyCh)
START:
// If the stream is closed and there's no data buffered, return EOF
s.stateLock.Lock()
switch s.state {
case streamLocalClose:
fallthrough
// LocalClose only prohibits further local writes. Handle reads normally.
case streamRemoteClose:
fallthrough
case streamClosed:
@@ -138,19 +140,22 @@ WAIT:
var timer *time.Timer
readDeadline := s.readDeadline.Load().(time.Time)
if !readDeadline.IsZero() {
delay := readDeadline.Sub(time.Now())
delay := time.Until(readDeadline)
timer = time.NewTimer(delay)
timeout = timer.C
}
select {
case <-s.session.shutdownCh:
case <-s.recvNotifyCh:
if timer != nil {
timer.Stop()
}
goto START
case <-timeout:
return 0, ErrTimeout
}
if timer != nil {
if !timer.Stop() {
<-timeout
}
}
goto START
}
// Write is used to write to the stream
@@ -219,18 +224,25 @@ START:
WAIT:
var timeout <-chan time.Time
var timer *time.Timer
writeDeadline := s.writeDeadline.Load().(time.Time)
if !writeDeadline.IsZero() {
delay := writeDeadline.Sub(time.Now())
timeout = time.After(delay)
delay := time.Until(writeDeadline)
timer = time.NewTimer(delay)
timeout = timer.C
}
select {
case <-s.session.shutdownCh:
case <-s.sendNotifyCh:
goto START
case <-timeout:
return 0, ErrTimeout
}
return 0, nil
if timer != nil {
if !timer.Stop() {
<-timeout
}
}
goto START
}
// sendFlags determines any flags that are appropriate
@@ -380,7 +392,7 @@ func (s *Stream) closeTimeout() {
defer s.sendLock.Unlock()
hdr := header(make([]byte, headerSize))
hdr.encode(typeWindowUpdate, flagRST, s.id, 0)
s.session.sendNoWait(hdr)
_ = s.session.sendNoWait(hdr)
}
// forceClose is used for when the session is exiting
+7
View File
@@ -5,6 +5,13 @@ import (
"time"
)
// Logger is a abstract of *log.Logger
type Logger interface {
Print(v ...interface{})
Printf(format string, v ...interface{})
Println(v ...interface{})
}
var (
timerPool = &sync.Pool{
New: func() interface{} {