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