Commit 3dd5bb53 authored by Kirill Smelkov's avatar Kirill Smelkov

X pipenet: Don't use 0 port in exchanges -- like with IP it is used only to...

X pipenet: Don't use 0 port in exchanges -- like with IP it is used only to signal autobind to listen
parent 1f89aa94
......@@ -83,7 +83,7 @@ type Host struct {
name string
// NOTE protected by Network.mu
socketv []*socket // port -> listener | conn
socketv []*socket // port -> listener | conn ; [0] is always nil
}
var _ xnet.Networker = (*Host)(nil)
......@@ -176,14 +176,14 @@ func (h *Host) resolveAddr(addr string) (host *Host, port int, err error) {
return nil, 0, &net.AddrError{Err: "no such host", Addr: addr}
}
return host, port, nil
return host, a.Port, nil
}
// XXX temp
//trace:event traceListen(laddr string)
// Listen starts new listener
// It either allocates free port if laddr is "", or binds to laddr.
// It either allocates free port if laddr is "" or with 0 port, or binds to laddr.
// Once listener is started, Dials could connect to listening address.
// Connection requests created by Dials could be accepted via Accept.
func (h *Host) Listen(laddr string) (net.Listener, error) {
......@@ -193,28 +193,32 @@ func (h *Host) Listen(laddr string) (net.Listener, error) {
var sk *socket
// find first free port if autobind requested
if laddr == "" {
sk = h.allocFreeSocket()
laddr = ":0"
}
// else we resolve/verify address, check whether it is already used, and if not allocate socket in-place
} else {
var netladdr net.Addr
lerr := func(err error) error {
return &net.OpError{Op: "listen", Net: h.Network(), Addr: netladdr, Err: err}
}
var netladdr net.Addr
lerr := func(err error) error {
return &net.OpError{Op: "listen", Net: h.Network(), Addr: netladdr, Err: err}
}
host, port, err := h.resolveAddr(laddr)
if err != nil {
return nil, lerr(err)
}
host, port, err := h.resolveAddr(laddr)
if err != nil {
return nil, lerr(err)
}
netladdr = &Addr{Net: h.Network(), Host: host.name, Port: port}
netladdr = &Addr{Net: h.Network(), Host: host.name, Port: port}
if host != h {
return nil, lerr(errAddrNoListen)
}
if host != h {
return nil, lerr(errAddrNoListen)
}
// find first free port if autobind requested
if port == 0 {
sk = h.allocFreeSocket()
// else allocate socket in-place
} else {
// grow if needed
for port >= len(h.socketv) {
h.socketv = append(h.socketv, nil)
......@@ -378,17 +382,17 @@ func (c *conn) RemoteAddr() net.Addr {
// ----------------------------------------
// allocFreeSocket finds first free port and allocates socket entry for it
// allocFreeSocket finds first free port and allocates socket entry for it.
// must be called with Network.mu held
func (h *Host) allocFreeSocket() *socket {
// find first free port
port := 0
port := 1 // never allocate port 0 - it is used for autobind on listen only
for ; port < len(h.socketv); port++ {
if h.socketv[port] == nil {
break
}
}
// if all busy it exits with port == len(h.socketv)
// if all busy it exits with port >= len(h.socketv)
// grow if needed
for port >= len(h.socketv) {
......
......@@ -103,41 +103,45 @@ func TestPipeNet(t *testing.T) {
assertEq(t, err, &net.OpError{Op: "dial", Net: "pipet", Addr: xaddr("α:0"), Err: errConnRefused})
l1 := xlisten(, "")
assertEq(t, l1.Addr(), xaddr("α:0"))
assertEq(t, l1.Addr(), xaddr("α:1"))
// zero port always stays unused even after autobind
_, err = .Dial(context.Background(), ":0")
assertEq(t, err, &net.OpError{Op: "dial", Net: "pipet", Addr: xaddr("α:0"), Err: errConnRefused})
wg := &xsync.WorkGroup{}
wg.Gox(func() {
c1s := xaccept(l1)
assertEq(t, c1s.LocalAddr(), xaddr("α:1"))
assertEq(t, c1s.RemoteAddr(), xaddr("β:0"))
assertEq(t, c1s.LocalAddr(), xaddr("α:2"))
assertEq(t, c1s.RemoteAddr(), xaddr("β:1"))
assertEq(t, xread(c1s), "ping")
xwrite(c1s, "pong")
c2s := xaccept(l1)
assertEq(t, c2s.LocalAddr(), xaddr("α:2"))
assertEq(t, c2s.RemoteAddr(), xaddr("β:1"))
assertEq(t, c2s.LocalAddr(), xaddr("α:3"))
assertEq(t, c2s.RemoteAddr(), xaddr("β:2"))
assertEq(t, xread(c2s), "hello")
xwrite(c2s, "world")
})
c1c := xdial(, "α:0")
assertEq(t, c1c.LocalAddr(), xaddr("β:0"))
assertEq(t, c1c.RemoteAddr(), xaddr("α:1"))
c1c := xdial(, "α:1")
assertEq(t, c1c.LocalAddr(), xaddr("β:1"))
assertEq(t, c1c.RemoteAddr(), xaddr("α:2"))
xwrite(c1c, "ping")
assertEq(t, xread(c1c), "pong")
c2c := xdial(, "α:0")
assertEq(t, c2c.LocalAddr(), xaddr("β:1"))
assertEq(t, c2c.RemoteAddr(), xaddr("α:2"))
c2c := xdial(, "α:1")
assertEq(t, c2c.LocalAddr(), xaddr("β:2"))
assertEq(t, c2c.RemoteAddr(), xaddr("α:3"))
xwrite(c2c, "hello")
assertEq(t, xread(c2c), "world")
xwait(wg)
l2 := xlisten(, "")
assertEq(t, l2.Addr(), xaddr("α:3"))
l2 := xlisten(, ":0") // autobind again
assertEq(t, l2.Addr(), xaddr("α:4"))
}
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