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