mirror of
https://github.com/golang/go
synced 2024-10-05 07:11:22 -06:00
519474451a
This is a subset of https://golang.org/cl/20022 with only the copyright header lines, so the next CL will be smaller and more reviewable. Go policy has been single space after periods in comments for some time. The copyright header template at: https://golang.org/doc/contribute.html#copyright also uses a single space. Make them all consistent. Change-Id: Icc26c6b8495c3820da6b171ca96a74701b4a01b0 Reviewed-on: https://go-review.googlesource.com/20111 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
215 lines
5.8 KiB
Go
215 lines
5.8 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
|
|
|
|
package net
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
|
|
// address that can be converted into a syscall.Sockaddr.
|
|
type sockaddr interface {
|
|
Addr
|
|
|
|
// family returns the platform-dependent address family
|
|
// identifier.
|
|
family() int
|
|
|
|
// isWildcard reports whether the address is a wildcard
|
|
// address.
|
|
isWildcard() bool
|
|
|
|
// sockaddr returns the address converted into a syscall
|
|
// sockaddr type that implements syscall.Sockaddr
|
|
// interface. It returns a nil interface when the address is
|
|
// nil.
|
|
sockaddr(family int) (syscall.Sockaddr, error)
|
|
}
|
|
|
|
// socket returns a network file descriptor that is ready for
|
|
// asynchronous I/O using the network poller.
|
|
func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time, cancel <-chan struct{}) (fd *netFD, err error) {
|
|
s, err := sysSocket(family, sotype, proto)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
|
|
closeFunc(s)
|
|
return nil, err
|
|
}
|
|
if fd, err = newFD(s, family, sotype, net); err != nil {
|
|
closeFunc(s)
|
|
return nil, err
|
|
}
|
|
|
|
// This function makes a network file descriptor for the
|
|
// following applications:
|
|
//
|
|
// - An endpoint holder that opens a passive stream
|
|
// connection, known as a stream listener
|
|
//
|
|
// - An endpoint holder that opens a destination-unspecific
|
|
// datagram connection, known as a datagram listener
|
|
//
|
|
// - An endpoint holder that opens an active stream or a
|
|
// destination-specific datagram connection, known as a
|
|
// dialer
|
|
//
|
|
// - An endpoint holder that opens the other connection, such
|
|
// as talking to the protocol stack inside the kernel
|
|
//
|
|
// For stream and datagram listeners, they will only require
|
|
// named sockets, so we can assume that it's just a request
|
|
// from stream or datagram listeners when laddr is not nil but
|
|
// raddr is nil. Otherwise we assume it's just for dialers or
|
|
// the other connection holders.
|
|
|
|
if laddr != nil && raddr == nil {
|
|
switch sotype {
|
|
case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
|
|
if err := fd.listenStream(laddr, listenerBacklog); err != nil {
|
|
fd.Close()
|
|
return nil, err
|
|
}
|
|
return fd, nil
|
|
case syscall.SOCK_DGRAM:
|
|
if err := fd.listenDatagram(laddr); err != nil {
|
|
fd.Close()
|
|
return nil, err
|
|
}
|
|
return fd, nil
|
|
}
|
|
}
|
|
if err := fd.dial(laddr, raddr, deadline, cancel); err != nil {
|
|
fd.Close()
|
|
return nil, err
|
|
}
|
|
return fd, nil
|
|
}
|
|
|
|
func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
|
|
switch fd.family {
|
|
case syscall.AF_INET, syscall.AF_INET6:
|
|
switch fd.sotype {
|
|
case syscall.SOCK_STREAM:
|
|
return sockaddrToTCP
|
|
case syscall.SOCK_DGRAM:
|
|
return sockaddrToUDP
|
|
case syscall.SOCK_RAW:
|
|
return sockaddrToIP
|
|
}
|
|
case syscall.AF_UNIX:
|
|
switch fd.sotype {
|
|
case syscall.SOCK_STREAM:
|
|
return sockaddrToUnix
|
|
case syscall.SOCK_DGRAM:
|
|
return sockaddrToUnixgram
|
|
case syscall.SOCK_SEQPACKET:
|
|
return sockaddrToUnixpacket
|
|
}
|
|
}
|
|
return func(syscall.Sockaddr) Addr { return nil }
|
|
}
|
|
|
|
func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, cancel <-chan struct{}) error {
|
|
var err error
|
|
var lsa syscall.Sockaddr
|
|
if laddr != nil {
|
|
if lsa, err = laddr.sockaddr(fd.family); err != nil {
|
|
return err
|
|
} else if lsa != nil {
|
|
if err := syscall.Bind(fd.sysfd, lsa); err != nil {
|
|
return os.NewSyscallError("bind", err)
|
|
}
|
|
}
|
|
}
|
|
var rsa syscall.Sockaddr
|
|
if raddr != nil {
|
|
if rsa, err = raddr.sockaddr(fd.family); err != nil {
|
|
return err
|
|
}
|
|
if err := fd.connect(lsa, rsa, deadline, cancel); err != nil {
|
|
return err
|
|
}
|
|
fd.isConnected = true
|
|
} else {
|
|
if err := fd.init(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
lsa, _ = syscall.Getsockname(fd.sysfd)
|
|
if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
|
|
fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
|
|
} else {
|
|
fd.setAddr(fd.addrFunc()(lsa), raddr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
|
|
if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
|
|
return err
|
|
}
|
|
if lsa, err := laddr.sockaddr(fd.family); err != nil {
|
|
return err
|
|
} else if lsa != nil {
|
|
if err := syscall.Bind(fd.sysfd, lsa); err != nil {
|
|
return os.NewSyscallError("bind", err)
|
|
}
|
|
}
|
|
if err := listenFunc(fd.sysfd, backlog); err != nil {
|
|
return os.NewSyscallError("listen", err)
|
|
}
|
|
if err := fd.init(); err != nil {
|
|
return err
|
|
}
|
|
lsa, _ := syscall.Getsockname(fd.sysfd)
|
|
fd.setAddr(fd.addrFunc()(lsa), nil)
|
|
return nil
|
|
}
|
|
|
|
func (fd *netFD) listenDatagram(laddr sockaddr) error {
|
|
switch addr := laddr.(type) {
|
|
case *UDPAddr:
|
|
// We provide a socket that listens to a wildcard
|
|
// address with reusable UDP port when the given laddr
|
|
// is an appropriate UDP multicast address prefix.
|
|
// This makes it possible for a single UDP listener to
|
|
// join multiple different group addresses, for
|
|
// multiple UDP listeners that listen on the same UDP
|
|
// port to join the same group address.
|
|
if addr.IP != nil && addr.IP.IsMulticast() {
|
|
if err := setDefaultMulticastSockopts(fd.sysfd); err != nil {
|
|
return err
|
|
}
|
|
addr := *addr
|
|
switch fd.family {
|
|
case syscall.AF_INET:
|
|
addr.IP = IPv4zero
|
|
case syscall.AF_INET6:
|
|
addr.IP = IPv6unspecified
|
|
}
|
|
laddr = &addr
|
|
}
|
|
}
|
|
if lsa, err := laddr.sockaddr(fd.family); err != nil {
|
|
return err
|
|
} else if lsa != nil {
|
|
if err := syscall.Bind(fd.sysfd, lsa); err != nil {
|
|
return os.NewSyscallError("bind", err)
|
|
}
|
|
}
|
|
if err := fd.init(); err != nil {
|
|
return err
|
|
}
|
|
lsa, _ := syscall.Getsockname(fd.sysfd)
|
|
fd.setAddr(fd.addrFunc()(lsa), nil)
|
|
return nil
|
|
}
|