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