src/pkg/net/file.go - The Go Programming Language

Golang

Source file src/pkg/net/file.go

     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 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 := syscall.Dup(int(f.Fd()))
    16		if err != nil {
    17			return nil, os.NewSyscallError("dup", err)
    18		}
    19	
    20		proto, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
    21		if err != nil {
    22			return nil, os.NewSyscallError("getsockopt", err)
    23		}
    24	
    25		family := syscall.AF_UNSPEC
    26		toAddr := sockaddrToTCP
    27		sa, _ := syscall.Getsockname(fd)
    28		switch sa.(type) {
    29		default:
    30			closesocket(fd)
    31			return nil, syscall.EINVAL
    32		case *syscall.SockaddrInet4:
    33			family = syscall.AF_INET
    34			if proto == syscall.SOCK_DGRAM {
    35				toAddr = sockaddrToUDP
    36			} else if proto == syscall.SOCK_RAW {
    37				toAddr = sockaddrToIP
    38			}
    39		case *syscall.SockaddrInet6:
    40			family = syscall.AF_INET6
    41			if proto == syscall.SOCK_DGRAM {
    42				toAddr = sockaddrToUDP
    43			} else if proto == syscall.SOCK_RAW {
    44				toAddr = sockaddrToIP
    45			}
    46		case *syscall.SockaddrUnix:
    47			family = syscall.AF_UNIX
    48			toAddr = sockaddrToUnix
    49			if proto == syscall.SOCK_DGRAM {
    50				toAddr = sockaddrToUnixgram
    51			} else if proto == syscall.SOCK_SEQPACKET {
    52				toAddr = sockaddrToUnixpacket
    53			}
    54		}
    55		laddr := toAddr(sa)
    56		sa, _ = syscall.Getpeername(fd)
    57		raddr := toAddr(sa)
    58	
    59		netfd, err := newFD(fd, family, proto, laddr.Network())
    60		if err != nil {
    61			return nil, err
    62		}
    63		netfd.setAddr(laddr, raddr)
    64		return netfd, nil
    65	}
    66	
    67	// FileConn returns a copy of the network connection corresponding to
    68	// the open file f.  It is the caller's responsibility to close f when
    69	// finished.  Closing c does not affect f, and closing f does not
    70	// affect c.
    71	func FileConn(f *os.File) (c Conn, err error) {
    72		fd, err := newFileFD(f)
    73		if err != nil {
    74			return nil, err
    75		}
    76		switch fd.laddr.(type) {
    77		case *TCPAddr:
    78			return newTCPConn(fd), nil
    79		case *UDPAddr:
    80			return newUDPConn(fd), nil
    81		case *UnixAddr:
    82			return newUnixConn(fd), nil
    83		case *IPAddr:
    84			return newIPConn(fd), nil
    85		}
    86		fd.Close()
    87		return nil, syscall.EINVAL
    88	}
    89	
    90	// FileListener returns a copy of the network listener corresponding
    91	// to the open file f.  It is the caller's responsibility to close l
    92	// when finished.  Closing c does not affect l, and closing l does not
    93	// affect c.
    94	func FileListener(f *os.File) (l Listener, err error) {
    95		fd, err := newFileFD(f)
    96		if err != nil {
    97			return nil, err
    98		}
    99		switch laddr := fd.laddr.(type) {
   100		case *TCPAddr:
   101			return &TCPListener{fd}, nil
   102		case *UnixAddr:
   103			return &UnixListener{fd, laddr.Name}, nil
   104		}
   105		fd.Close()
   106		return nil, syscall.EINVAL
   107	}
   108	
   109	// FilePacketConn returns a copy of the packet network connection
   110	// corresponding to the open file f.  It is the caller's
   111	// responsibility to close f when finished.  Closing c does not affect
   112	// f, and closing f does not affect c.
   113	func FilePacketConn(f *os.File) (c PacketConn, err error) {
   114		fd, err := newFileFD(f)
   115		if err != nil {
   116			return nil, err
   117		}
   118		switch fd.laddr.(type) {
   119		case *UDPAddr:
   120			return newUDPConn(fd), nil
   121		case *UnixAddr:
   122			return newUnixConn(fd), nil
   123		}
   124		fd.Close()
   125		return nil, syscall.EINVAL
   126	}