Home | History | Annotate | Download | only in net
      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 solaris
      6 
      7 package net
      8 
      9 import (
     10 	"internal/poll"
     11 	"os"
     12 	"syscall"
     13 )
     14 
     15 func dupSocket(f *os.File) (int, error) {
     16 	s, err := dupCloseOnExec(int(f.Fd()))
     17 	if err != nil {
     18 		return -1, err
     19 	}
     20 	if err := syscall.SetNonblock(s, true); err != nil {
     21 		poll.CloseFunc(s)
     22 		return -1, os.NewSyscallError("setnonblock", err)
     23 	}
     24 	return s, nil
     25 }
     26 
     27 func newFileFD(f *os.File) (*netFD, error) {
     28 	s, err := dupSocket(f)
     29 	if err != nil {
     30 		return nil, err
     31 	}
     32 	family := syscall.AF_UNSPEC
     33 	sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE)
     34 	if err != nil {
     35 		poll.CloseFunc(s)
     36 		return nil, os.NewSyscallError("getsockopt", err)
     37 	}
     38 	lsa, _ := syscall.Getsockname(s)
     39 	rsa, _ := syscall.Getpeername(s)
     40 	switch lsa.(type) {
     41 	case *syscall.SockaddrInet4:
     42 		family = syscall.AF_INET
     43 	case *syscall.SockaddrInet6:
     44 		family = syscall.AF_INET6
     45 	case *syscall.SockaddrUnix:
     46 		family = syscall.AF_UNIX
     47 	default:
     48 		poll.CloseFunc(s)
     49 		return nil, syscall.EPROTONOSUPPORT
     50 	}
     51 	fd, err := newFD(s, family, sotype, "")
     52 	if err != nil {
     53 		poll.CloseFunc(s)
     54 		return nil, err
     55 	}
     56 	laddr := fd.addrFunc()(lsa)
     57 	raddr := fd.addrFunc()(rsa)
     58 	fd.net = laddr.Network()
     59 	if err := fd.init(); err != nil {
     60 		fd.Close()
     61 		return nil, err
     62 	}
     63 	fd.setAddr(laddr, raddr)
     64 	return fd, nil
     65 }
     66 
     67 func fileConn(f *os.File) (Conn, error) {
     68 	fd, err := newFileFD(f)
     69 	if err != nil {
     70 		return nil, err
     71 	}
     72 	switch fd.laddr.(type) {
     73 	case *TCPAddr:
     74 		return newTCPConn(fd), nil
     75 	case *UDPAddr:
     76 		return newUDPConn(fd), nil
     77 	case *IPAddr:
     78 		return newIPConn(fd), nil
     79 	case *UnixAddr:
     80 		return newUnixConn(fd), nil
     81 	}
     82 	fd.Close()
     83 	return nil, syscall.EINVAL
     84 }
     85 
     86 func fileListener(f *os.File) (Listener, error) {
     87 	fd, err := newFileFD(f)
     88 	if err != nil {
     89 		return nil, err
     90 	}
     91 	switch laddr := fd.laddr.(type) {
     92 	case *TCPAddr:
     93 		return &TCPListener{fd}, nil
     94 	case *UnixAddr:
     95 		return &UnixListener{fd: fd, path: laddr.Name, unlink: false}, nil
     96 	}
     97 	fd.Close()
     98 	return nil, syscall.EINVAL
     99 }
    100 
    101 func filePacketConn(f *os.File) (PacketConn, error) {
    102 	fd, err := newFileFD(f)
    103 	if err != nil {
    104 		return nil, err
    105 	}
    106 	switch fd.laddr.(type) {
    107 	case *UDPAddr:
    108 		return newUDPConn(fd), nil
    109 	case *IPAddr:
    110 		return newIPConn(fd), nil
    111 	case *UnixAddr:
    112 		return newUnixConn(fd), nil
    113 	}
    114 	fd.Close()
    115 	return nil, syscall.EINVAL
    116 }
    117