github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/net/file_unix.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build darwin dragonfly freebsd linux netbsd openbsd
     6  
     7  package net
     8  
     9  import (
    10  	"os"
    11  	"syscall"
    12  )
    13  
    14  func newFileFD(f *os.File) (*netFD, error) {
    15  	fd, err := dupCloseOnExec(int(f.Fd()))
    16  	if err != nil {
    17  		return nil, os.NewSyscallError("dup", err)
    18  	}
    19  
    20  	if err = syscall.SetNonblock(fd, true); err != nil {
    21  		closesocket(fd)
    22  		return nil, err
    23  	}
    24  
    25  	sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
    26  	if err != nil {
    27  		closesocket(fd)
    28  		return nil, os.NewSyscallError("getsockopt", err)
    29  	}
    30  
    31  	family := syscall.AF_UNSPEC
    32  	toAddr := sockaddrToTCP
    33  	lsa, _ := syscall.Getsockname(fd)
    34  	switch lsa.(type) {
    35  	default:
    36  		closesocket(fd)
    37  		return nil, syscall.EINVAL
    38  	case *syscall.SockaddrInet4:
    39  		family = syscall.AF_INET
    40  		if sotype == syscall.SOCK_DGRAM {
    41  			toAddr = sockaddrToUDP
    42  		} else if sotype == syscall.SOCK_RAW {
    43  			toAddr = sockaddrToIP
    44  		}
    45  	case *syscall.SockaddrInet6:
    46  		family = syscall.AF_INET6
    47  		if sotype == syscall.SOCK_DGRAM {
    48  			toAddr = sockaddrToUDP
    49  		} else if sotype == syscall.SOCK_RAW {
    50  			toAddr = sockaddrToIP
    51  		}
    52  	case *syscall.SockaddrUnix:
    53  		family = syscall.AF_UNIX
    54  		toAddr = sockaddrToUnix
    55  		if sotype == syscall.SOCK_DGRAM {
    56  			toAddr = sockaddrToUnixgram
    57  		} else if sotype == syscall.SOCK_SEQPACKET {
    58  			toAddr = sockaddrToUnixpacket
    59  		}
    60  	}
    61  	laddr := toAddr(lsa)
    62  	rsa, _ := syscall.Getpeername(fd)
    63  	raddr := toAddr(rsa)
    64  
    65  	netfd, err := newFD(fd, family, sotype, laddr.Network())
    66  	if err != nil {
    67  		closesocket(fd)
    68  		return nil, err
    69  	}
    70  	if err := netfd.init(); err != nil {
    71  		netfd.Close()
    72  		return nil, err
    73  	}
    74  	netfd.setAddr(laddr, raddr)
    75  	return netfd, nil
    76  }
    77  
    78  // FileConn returns a copy of the network connection corresponding to
    79  // the open file f.  It is the caller's responsibility to close f when
    80  // finished.  Closing c does not affect f, and closing f does not
    81  // affect c.
    82  func FileConn(f *os.File) (c Conn, err error) {
    83  	fd, err := newFileFD(f)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	switch fd.laddr.(type) {
    88  	case *TCPAddr:
    89  		return newTCPConn(fd), nil
    90  	case *UDPAddr:
    91  		return newUDPConn(fd), nil
    92  	case *IPAddr:
    93  		return newIPConn(fd), nil
    94  	case *UnixAddr:
    95  		return newUnixConn(fd), nil
    96  	}
    97  	fd.Close()
    98  	return nil, syscall.EINVAL
    99  }
   100  
   101  // FileListener returns a copy of the network listener corresponding
   102  // to the open file f.  It is the caller's responsibility to close l
   103  // when finished.  Closing l does not affect f, and closing f does not
   104  // affect l.
   105  func FileListener(f *os.File) (l Listener, err error) {
   106  	fd, err := newFileFD(f)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	switch laddr := fd.laddr.(type) {
   111  	case *TCPAddr:
   112  		return &TCPListener{fd}, nil
   113  	case *UnixAddr:
   114  		return &UnixListener{fd, laddr.Name}, nil
   115  	}
   116  	fd.Close()
   117  	return nil, syscall.EINVAL
   118  }
   119  
   120  // FilePacketConn returns a copy of the packet network connection
   121  // corresponding to the open file f.  It is the caller's
   122  // responsibility to close f when finished.  Closing c does not affect
   123  // f, and closing f does not affect c.
   124  func FilePacketConn(f *os.File) (c PacketConn, err error) {
   125  	fd, err := newFileFD(f)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	switch fd.laddr.(type) {
   130  	case *UDPAddr:
   131  		return newUDPConn(fd), nil
   132  	case *UnixAddr:
   133  		return newUnixConn(fd), nil
   134  	}
   135  	fd.Close()
   136  	return nil, syscall.EINVAL
   137  }