]> Cypherpunks repositories - gostls13.git/commitdiff
net: add unixpacket
authorAlbert Strasheim <fullung@gmail.com>
Wed, 19 Jan 2011 19:21:58 +0000 (14:21 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 19 Jan 2011 19:21:58 +0000 (14:21 -0500)
R=golang-dev, rsc, rsc1
CC=golang-dev
https://golang.org/cl/2309043

src/pkg/net/dial.go
src/pkg/net/net_test.go
src/pkg/net/server_test.go
src/pkg/net/unixsock.go

index 9a4c8f68893d0c2b0aff58138d138120fc963774..03b9d87be33d58e36096949978e21dc47355571a 100644 (file)
@@ -59,7 +59,7 @@ func Dial(net, laddr, raddr string) (c Conn, err os.Error) {
                        return nil, err
                }
                return c, nil
-       case "unix", "unixgram":
+       case "unix", "unixgram", "unixpacket":
                var la, ra *UnixAddr
                if raddr != "" {
                        if ra, err = ResolveUnixAddr(net, raddr); err != nil {
@@ -102,7 +102,7 @@ Error:
 
 // Listen announces on the local network address laddr.
 // The network string net must be a stream-oriented
-// network: "tcp", "tcp4", "tcp6", or "unix".
+// network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket".
 func Listen(net, laddr string) (l Listener, err os.Error) {
        switch net {
        case "tcp", "tcp4", "tcp6":
@@ -117,7 +117,7 @@ func Listen(net, laddr string) (l Listener, err os.Error) {
                        return nil, err
                }
                return l, nil
-       case "unix":
+       case "unix", "unixpacket":
                var la *UnixAddr
                if laddr != "" {
                        if la, err = ResolveUnixAddr(net, laddr); err != nil {
index b303254c6358460d14b9fe1e030352678e202f92..1de7a856a700f4c89f2630644afbbbd32565dedb 100644 (file)
@@ -52,6 +52,14 @@ var dialErrorTests = []DialErrorTest{
                "unix", "", "/etc/",
                "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
        },
+       {
+               "unixpacket", "", "/etc/file-not-found",
+               "dial unixpacket /etc/file-not-found: no such file or directory",
+       },
+       {
+               "unixpacket", "", "/etc/",
+               "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
+       },
 }
 
 func TestDialError(t *testing.T) {
index 46bedaa5bcbb8b850c1cee0a8a0f6aaee234e392..e3f718a59dc558ea0d287f01b3f69e8b48b105ea 100644 (file)
@@ -116,9 +116,14 @@ func TestUnixServer(t *testing.T) {
        os.Remove("/tmp/gotest.net")
        doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
        os.Remove("/tmp/gotest.net")
+       if syscall.OS != "darwin" {
+               doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
+               os.Remove("/tmp/gotest.net")
+       }
        if syscall.OS == "linux" {
                // Test abstract unix domain socket, a Linux-ism
                doTest(t, "unix", "@gotest/net", "@gotest/net")
+               doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
        }
 }
 
index 2521969eb0981b6d1170df6f7caca00d6eef2a24..8c26a7bafd50a8ed4f52d42d64364987dbce0512 100644 (file)
@@ -20,6 +20,8 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
                proto = syscall.SOCK_STREAM
        case "unixgram":
                proto = syscall.SOCK_DGRAM
+       case "unixpacket":
+               proto = syscall.SOCK_SEQPACKET
        }
 
        var la, ra syscall.Sockaddr
@@ -48,9 +50,12 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
        }
 
        f := sockaddrToUnix
-       if proto != syscall.SOCK_STREAM {
+       if proto == syscall.SOCK_DGRAM {
                f = sockaddrToUnixgram
+       } else if proto == syscall.SOCK_SEQPACKET {
+               f = sockaddrToUnixpacket
        }
+
        fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
        if oserr != nil {
                goto Error
@@ -67,30 +72,48 @@ Error:
 
 // UnixAddr represents the address of a Unix domain socket end point.
 type UnixAddr struct {
-       Name     string
-       Datagram bool
+       Name string
+       Net  string
 }
 
 func sockaddrToUnix(sa syscall.Sockaddr) Addr {
        if s, ok := sa.(*syscall.SockaddrUnix); ok {
-               return &UnixAddr{s.Name, false}
+               return &UnixAddr{s.Name, "unix"}
        }
        return nil
 }
 
 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
        if s, ok := sa.(*syscall.SockaddrUnix); ok {
-               return &UnixAddr{s.Name, true}
+               return &UnixAddr{s.Name, "unixgram"}
        }
        return nil
 }
 
-// Network returns the address's network name, "unix" or "unixgram".
-func (a *UnixAddr) Network() string {
-       if a == nil || !a.Datagram {
+func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
+       if s, ok := sa.(*syscall.SockaddrUnix); ok {
+               return &UnixAddr{s.Name, "unixpacket"}
+       }
+       return nil
+}
+
+func protoToNet(proto int) string {
+       switch proto {
+       case syscall.SOCK_STREAM:
                return "unix"
+       case syscall.SOCK_SEQPACKET:
+               return "unixpacket"
+       case syscall.SOCK_DGRAM:
+               return "unixgram"
+       default:
+               panic("protoToNet unknown protocol")
        }
-       return "unixgram"
+       return ""
+}
+
+// Network returns the address's network name, "unix" or "unixgram".
+func (a *UnixAddr) Network() string {
+       return a.Net
 }
 
 func (a *UnixAddr) String() string {
@@ -108,17 +131,17 @@ func (a *UnixAddr) toAddr() Addr {
 }
 
 // ResolveUnixAddr parses addr as a Unix domain socket address.
-// The string net gives the network name, "unix" or "unixgram".
+// The string net gives the network name, "unix", "unixgram" or
+// "unixpacket".
 func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) {
-       var datagram bool
        switch net {
        case "unix":
+       case "unixpacket":
        case "unixgram":
-               datagram = true
        default:
                return nil, UnknownNetworkError(net)
        }
-       return &UnixAddr{addr, datagram}, nil
+       return &UnixAddr{addr, net}, nil
 }
 
 // UnixConn is an implementation of the Conn interface
@@ -234,7 +257,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error)
        n, sa, err := c.fd.ReadFrom(b)
        switch sa := sa.(type) {
        case *syscall.SockaddrUnix:
-               addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM}
+               addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
        }
        return
 }
@@ -258,7 +281,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
        if !c.ok() {
                return 0, os.EINVAL
        }
-       if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) {
+       if addr.Net != protoToNet(c.fd.proto) {
                return 0, os.EAFNOSUPPORT
        }
        sa := &syscall.SockaddrUnix{Name: addr.Name}
@@ -284,7 +307,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
        n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
        switch sa := sa.(type) {
        case *syscall.SockaddrUnix:
-               addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM}
+               addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
        }
        return
 }
@@ -294,7 +317,7 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
                return 0, 0, os.EINVAL
        }
        if addr != nil {
-               if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) {
+               if addr.Net != protoToNet(c.fd.proto) {
                        return 0, 0, os.EAFNOSUPPORT
                }
                sa := &syscall.SockaddrUnix{Name: addr.Name}
@@ -330,11 +353,11 @@ type UnixListener struct {
 // ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
 // Net must be "unix" (stream sockets).
 func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
-       if net != "unix" && net != "unixgram" {
+       if net != "unix" && net != "unixgram" && net != "unixpacket" {
                return nil, UnknownNetworkError(net)
        }
        if laddr != nil {
-               laddr = &UnixAddr{laddr.Name, net == "unixgram"} // make our own copy
+               laddr = &UnixAddr{laddr.Name, net} // make our own copy
        }
        fd, err := unixSocket(net, laddr, nil, "listen")
        if err != nil {