go/src/net/file_unix.go
Dave Cheney f6d43b746a net: fix undetected set and not used error
Fixes an error where the compiler did not spot that the shadowed err
value was set again after being read. That second assignment was lost
as the value was redeclared in an inner scope.

Spotted by Gordon Klass, https://groups.google.com/forum/#!topic/golang-nuts/MdDLbvOjb4o

Change-Id: I28f2da6f98c52afcbb45e17d2b4f36c586598f98
Reviewed-on: https://go-review.googlesource.com/10600
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
2015-06-02 05:35:29 +00:00

185 lines
4.1 KiB
Go

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package net
import (
"internal/syscall/unix"
"os"
"syscall"
)
func dupSocket(f *os.File) (int, error) {
s, err := dupCloseOnExec(int(f.Fd()))
if err != nil {
return -1, err
}
if err := syscall.SetNonblock(s, true); err != nil {
closeFunc(s)
return -1, os.NewSyscallError("setnonblock", err)
}
return s, nil
}
func newFileFD(f *os.File, sa SocketAddr) (*netFD, error) {
s, err := dupSocket(f)
if err != nil {
return nil, err
}
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
}
laddr = sa.Addr(lsa)
raddr = sa.Addr(rsa)
fd, err = newFD(s, -1, -1, laddr.Network())
} else {
family := syscall.AF_UNSPEC
var sotype int
sotype, err = syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE)
if err != nil {
closeFunc(s)
return nil, os.NewSyscallError("getsockopt", err)
}
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
}
fd, err = newFD(s, family, sotype, "")
laddr = fd.addrFunc()(lsa)
raddr = fd.addrFunc()(rsa)
fd.net = laddr.Network()
}
if err != nil {
closeFunc(s)
return nil, err
}
if err := fd.init(); err != nil {
fd.Close()
return nil, err
}
fd.setAddr(laddr, raddr)
return fd, nil
}
func fileConn(f *os.File) (Conn, error) {
fd, err := newFileFD(f, nil)
if err != nil {
return nil, err
}
switch fd.laddr.(type) {
case *TCPAddr:
return newTCPConn(fd), nil
case *UDPAddr:
return newUDPConn(fd), nil
case *IPAddr:
return newIPConn(fd), nil
case *UnixAddr:
return newUnixConn(fd), nil
}
fd.Close()
return nil, syscall.EINVAL
}
func fileListener(f *os.File) (Listener, error) {
fd, err := newFileFD(f, nil)
if err != nil {
return nil, err
}
switch laddr := fd.laddr.(type) {
case *TCPAddr:
return &TCPListener{fd}, nil
case *UnixAddr:
return &UnixListener{fd, laddr.Name}, nil
}
fd.Close()
return nil, syscall.EINVAL
}
func filePacketConn(f *os.File) (PacketConn, error) {
fd, err := newFileFD(f, nil)
if err != nil {
return nil, err
}
switch fd.laddr.(type) {
case *UDPAddr:
return newUDPConn(fd), nil
case *IPAddr:
return newIPConn(fd), nil
case *UnixAddr:
return newUnixConn(fd), nil
}
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
}