diff options
author | Mikio Hara <mikioh.mikioh@gmail.com> | 2015-04-23 23:57:00 +0900 |
---|---|---|
committer | Mikio Hara <mikioh.mikioh@gmail.com> | 2015-05-13 01:04:23 +0000 |
commit | 6f7961da28232c609f7c51b3bed7f15db7dd33e1 (patch) | |
tree | a8a32603037c1e63e45c9361fd705076c1ee70ad /src/net/file_unix.go | |
parent | 08ba7dbdfdf0a2824ee122a6214e0263431a6ff0 (diff) | |
download | go-git-6f7961da28232c609f7c51b3bed7f15db7dd33e1.tar.gz |
net, internal/syscall/unix: add SocketConn, SocketPacketConn
FileConn and FilePacketConn APIs accept user-configured socket
descriptors to make them work together with runtime-integrated network
poller, but there's a limitation. The APIs reject protocol sockets that
are not supported by standard library. It's very hard for the net,
syscall packages to look after all platform, feature-specific sockets.
This change allows various platform, feature-specific socket descriptors
to use runtime-integrated network poller by using SocketConn,
SocketPacketConn APIs that bridge between the net, syscall packages and
platforms.
New exposed APIs:
pkg net, func SocketConn(*os.File, SocketAddr) (Conn, error)
pkg net, func SocketPacketConn(*os.File, SocketAddr) (PacketConn, error)
pkg net, type SocketAddr interface { Addr, Raw }
pkg net, type SocketAddr interface, Addr([]uint8) Addr
pkg net, type SocketAddr interface, Raw(Addr) []uint8
Fixes #10565.
Change-Id: Iec57499b3d84bb5cb0bcf3f664330c535eec11e3
Reviewed-on: https://go-review.googlesource.com/9275
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/net/file_unix.go')
-rw-r--r-- | src/net/file_unix.go | 157 |
1 files changed, 107 insertions, 50 deletions
diff --git a/src/net/file_unix.go b/src/net/file_unix.go index 147ca1ed95..df884d1603 100644 --- a/src/net/file_unix.go +++ b/src/net/file_unix.go @@ -7,76 +7,81 @@ package net import ( + "internal/syscall/unix" "os" "syscall" ) -func newFileFD(f *os.File) (*netFD, error) { - fd, err := dupCloseOnExec(int(f.Fd())) +func dupSocket(f *os.File) (int, error) { + s, err := dupCloseOnExec(int(f.Fd())) if err != nil { - return nil, err + return -1, err } - - if err = syscall.SetNonblock(fd, true); err != nil { - closeFunc(fd) - return nil, os.NewSyscallError("setnonblock", err) + if err := syscall.SetNonblock(s, true); err != nil { + closeFunc(s) + return -1, os.NewSyscallError("setnonblock", err) } + return s, nil +} - sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) +func newFileFD(f *os.File, sa SocketAddr) (*netFD, error) { + s, err := dupSocket(f) if err != nil { - closeFunc(fd) - return nil, os.NewSyscallError("getsockopt", err) + return nil, err } - - family := syscall.AF_UNSPEC - toAddr := sockaddrToTCP - lsa, _ := syscall.Getsockname(fd) - switch lsa.(type) { - case *syscall.SockaddrInet4: - family = syscall.AF_INET - if sotype == syscall.SOCK_DGRAM { - toAddr = sockaddrToUDP - } else if sotype == syscall.SOCK_RAW { - toAddr = sockaddrToIP + var laddr, raddr Addr + var fd *netFD + if sa != nil { + lsa := make([]byte, syscall.SizeofSockaddrAny) + if err := unix.Getsockname(s, lsa); err != nil { + lsa = nil + } + rsa := make([]byte, syscall.SizeofSockaddrAny) + if err := unix.Getpeername(s, rsa); err != nil { + rsa = nil } - case *syscall.SockaddrInet6: - family = syscall.AF_INET6 - if sotype == syscall.SOCK_DGRAM { - toAddr = sockaddrToUDP - } else if sotype == syscall.SOCK_RAW { - toAddr = sockaddrToIP + laddr = sa.Addr(lsa) + raddr = sa.Addr(rsa) + fd, err = newFD(s, -1, -1, laddr.Network()) + } else { + family := syscall.AF_UNSPEC + sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE) + if err != nil { + closeFunc(s) + return nil, os.NewSyscallError("getsockopt", err) } - case *syscall.SockaddrUnix: - family = syscall.AF_UNIX - toAddr = sockaddrToUnix - if sotype == syscall.SOCK_DGRAM { - toAddr = sockaddrToUnixgram - } else if sotype == syscall.SOCK_SEQPACKET { - toAddr = sockaddrToUnixpacket + lsa, _ := syscall.Getsockname(s) + rsa, _ := syscall.Getpeername(s) + switch lsa.(type) { + case *syscall.SockaddrInet4: + family = syscall.AF_INET + case *syscall.SockaddrInet6: + family = syscall.AF_INET6 + case *syscall.SockaddrUnix: + family = syscall.AF_UNIX + default: + closeFunc(s) + return nil, syscall.EPROTONOSUPPORT } - default: - closeFunc(fd) - return nil, syscall.EPROTONOSUPPORT + fd, err = newFD(s, family, sotype, "") + laddr = fd.addrFunc()(lsa) + raddr = fd.addrFunc()(rsa) + fd.net = laddr.Network() } - laddr := toAddr(lsa) - rsa, _ := syscall.Getpeername(fd) - raddr := toAddr(rsa) - - netfd, err := newFD(fd, family, sotype, laddr.Network()) if err != nil { - closeFunc(fd) + closeFunc(s) return nil, err } - if err := netfd.init(); err != nil { - netfd.Close() + if err := fd.init(); err != nil { + fd.Close() return nil, err } - netfd.setAddr(laddr, raddr) - return netfd, nil + fd.setAddr(laddr, raddr) + return fd, nil } func fileConn(f *os.File) (Conn, error) { - fd, err := newFileFD(f) + fd, err := newFileFD(f, nil) if err != nil { return nil, err } @@ -95,7 +100,7 @@ func fileConn(f *os.File) (Conn, error) { } func fileListener(f *os.File) (Listener, error) { - fd, err := newFileFD(f) + fd, err := newFileFD(f, nil) if err != nil { return nil, err } @@ -110,7 +115,7 @@ func fileListener(f *os.File) (Listener, error) { } func filePacketConn(f *os.File) (PacketConn, error) { - fd, err := newFileFD(f) + fd, err := newFileFD(f, nil) if err != nil { return nil, err } @@ -125,3 +130,55 @@ func filePacketConn(f *os.File) (PacketConn, error) { fd.Close() return nil, syscall.EINVAL } + +func socketConn(f *os.File, sa SocketAddr) (Conn, error) { + fd, err := newFileFD(f, sa) + if err != nil { + return nil, err + } + return &socketFile{conn: conn{fd}, SocketAddr: sa}, nil +} + +func socketPacketConn(f *os.File, sa SocketAddr) (PacketConn, error) { + fd, err := newFileFD(f, sa) + if err != nil { + return nil, err + } + return &socketFile{conn: conn{fd}, SocketAddr: sa}, nil +} + +var ( + _ Conn = &socketFile{} + _ PacketConn = &socketFile{} +) + +// A socketFile is a placeholder that holds a user-specified socket +// descriptor and a profile of socket address encoding. +// It implements both Conn and PacketConn interfaces. +type socketFile struct { + conn + SocketAddr +} + +func (c *socketFile) ReadFrom(b []byte) (int, Addr, error) { + if !c.ok() { + return 0, nil, syscall.EINVAL + } + from := make([]byte, syscall.SizeofSockaddrAny) + n, err := c.fd.recvFrom(b, 0, from) + if err != nil { + return n, nil, &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, c.SocketAddr.Addr(from), nil +} + +func (c *socketFile) WriteTo(b []byte, addr Addr) (int, error) { + if !c.ok() { + return 0, syscall.EINVAL + } + n, err := c.fd.sendTo(b, 0, c.SocketAddr.Raw(addr)) + if err != nil { + return n, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, nil +} |