Commit 03db1d8a authored by Kirill Smelkov's avatar Kirill Smelkov

go/neo/neonet: Demonstrate DialLink misbehaviour when all handshake attempts fail

Levin found that when all handshake attempts fail DialLink returns
both link=nil and err=nil which breaks what callers expect and lead to
segmentation fault when accessing that nil link.

-> Add test to demonstrate the problem.

With xfail removed that test currently fails as

    --- FAIL: TestDialLink_AllHandshakeErr (0.00s)
    panic: lab.nexedi.com/kirr/neo/go/neo/neonet.TestDialLink_AllHandshakeErr.gox.func4.1: lab.nexedi.com/kirr/neo/go/neo/neonet.TestDialLink_AllHandshakeErr.func2: DialLink to handshake-rejecting server:
    have: link=<nil> err=<nil>
    want: link=<nil> err=client:1 - server:2: handshake (client): unexpected EOF [recovered]

We will fix the problem in the next patch.

/reported-by @levin.zimmermann
/reported-at kirr/neo!10
parent f7776fc1
// Copyright (C) 2016-2023 Nexedi SA and Contributors.
// Copyright (C) 2016-2024 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
......@@ -28,6 +28,8 @@ import (
"testing"
"lab.nexedi.com/kirr/go123/exc"
"lab.nexedi.com/kirr/go123/xnet/pipenet"
"lab.nexedi.com/kirr/go123/xnet/virtnet"
"lab.nexedi.com/kirr/go123/xsync"
"lab.nexedi.com/kirr/neo/go/neo/proto"
)
......@@ -223,6 +225,70 @@ func _TestHandshake(t *T) {
}
}
// TestDialLink_AllHandshakeErr verifies that DialLink returns an error if all handshake attempts fail.
func TestDialLink_AllHandshakeErr(t *testing.T) {
t.Skip("xfail")
X := exc.Raiseif
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
net := pipenet.New("")
c := net.Host("client")
s := net.Host("server")
l, err := s.Listen(ctx, ":1"); X(err)
defer xclose(l)
allGood := false
wg := xsync.NewWorkGroup(ctx)
// server accepts all connections but rejects any handshake
gox(wg, func(ctx context.Context) {
for {
X(ctx.Err())
conn, err := l.Accept(ctx); X(err)
xclose(conn)
}
})
// client tries to connect and handshake with server, but handshake should fail
gox(wg, func(ctx context.Context) {
xaddr := func (addr string) *virtnet.Addr {
a, err := virtnet.ParseAddr(net.Network(), addr); X(err)
return a
}
errOk := &_HandshakeError{_LinkClient, xaddr("client:1"), xaddr("server:2"), io.ErrUnexpectedEOF}
var errHand *_HandshakeError
link, err := DialLink(ctx, c, "server:1")
if link == nil && errors.As(err, &errHand) {
// we cannot reliably reason about underlying IO error cause because it is
// set by another package internally. Stub that with io.ErrUnexpectedEOF .
errHand.Err = io.ErrUnexpectedEOF
if reflect.DeepEqual(errHand, errOk) {
allGood = true
cancel()
return
}
}
exc.Raisef("DialLink to handshake-rejecting server:\nhave: link=%v err=%v\nwant: link=%v err=%v",
link, err, nil, errOk)
})
err = wg.Wait()
if allGood {
if ctx.Err() == nil {
panic("all good but ctx not canceled")
}
err = nil
}
X(err)
}
// estr returns err.Error() or "<nil>".
func estr(err error) string {
if err == nil {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment