diff options
Diffstat (limited to 'libgo/go/net/ipsock_plan9.go')
-rw-r--r-- | libgo/go/net/ipsock_plan9.go | 80 |
1 files changed, 70 insertions, 10 deletions
diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go index 93f0f4e..2308236 100644 --- a/libgo/go/net/ipsock_plan9.go +++ b/libgo/go/net/ipsock_plan9.go @@ -57,17 +57,17 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) { return nil, 0, &ParseError{Type: "IP address", Text: s} } } - p, _, ok := dtoi(s[i+1:]) + p, plen, ok := dtoi(s[i+1:]) if !ok { return nil, 0, &ParseError{Type: "port", Text: s} } if p < 0 || p > 0xFFFF { - return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)} + return nil, 0, &AddrError{Err: "invalid port", Addr: s[i+1 : i+1+plen]} } return addr, p, nil } -func readPlan9Addr(proto, filename string) (addr Addr, err error) { +func readPlan9Addr(net, filename string) (addr Addr, err error) { var buf [128]byte f, err := os.Open(filename) @@ -83,13 +83,19 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) { if err != nil { return } - switch proto { - case "tcp": + switch net { + case "tcp4", "udp4": + if ip.Equal(IPv6zero) { + ip = ip[:IPv4len] + } + } + switch net { + case "tcp", "tcp4", "tcp6": addr = &TCPAddr{IP: ip, Port: port} - case "udp": + case "udp", "udp4", "udp6": addr = &UDPAddr{IP: ip, Port: port} default: - return nil, UnknownNetworkError(proto) + return nil, UnknownNetworkError(net) } return addr, nil } @@ -199,7 +205,11 @@ func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd * if err != nil { return nil, err } - _, err = f.WriteString("connect " + dest) + if la := plan9LocalAddr(laddr); la == "" { + err = hangupCtlWrite(ctx, proto, f, "connect "+dest) + } else { + err = hangupCtlWrite(ctx, proto, f, "connect "+dest+" "+la) + } if err != nil { f.Close() return nil, err @@ -209,7 +219,7 @@ func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd * f.Close() return nil, err } - laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local") + laddr, err = readPlan9Addr(net, netdir+"/"+proto+"/"+name+"/local") if err != nil { data.Close() f.Close() @@ -229,7 +239,7 @@ func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err er f.Close() return nil, &OpError{Op: "announce", Net: net, Source: laddr, Addr: nil, Err: err} } - laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local") + laddr, err = readPlan9Addr(net, netdir+"/"+proto+"/"+name+"/local") if err != nil { f.Close() return nil, err @@ -303,3 +313,53 @@ func toLocal(a Addr, net string) Addr { } return a } + +// plan9LocalAddr returns a Plan 9 local address string. +// See setladdrport at https://9p.io/sources/plan9/sys/src/9/ip/devip.c. +func plan9LocalAddr(addr Addr) string { + var ip IP + port := 0 + switch a := addr.(type) { + case *TCPAddr: + if a != nil { + ip = a.IP + port = a.Port + } + case *UDPAddr: + if a != nil { + ip = a.IP + port = a.Port + } + } + if len(ip) == 0 || ip.IsUnspecified() { + if port == 0 { + return "" + } + return itoa(port) + } + return ip.String() + "!" + itoa(port) +} + +func hangupCtlWrite(ctx context.Context, proto string, ctl *os.File, msg string) error { + if proto != "tcp" { + _, err := ctl.WriteString(msg) + return err + } + written := make(chan struct{}) + errc := make(chan error) + go func() { + select { + case <-ctx.Done(): + ctl.WriteString("hangup") + errc <- mapErr(ctx.Err()) + case <-written: + errc <- nil + } + }() + _, err := ctl.WriteString(msg) + close(written) + if e := <-errc; err == nil && e != nil { // we hung up + return e + } + return err +} |