...
Run Format

Source file src/pkg/net/tcpsock_posix.go

     1	// Copyright 2009 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 nacl netbsd openbsd solaris windows
     6	
     7	package net
     8	
     9	import (
    10		"io"
    11		"os"
    12		"syscall"
    13		"time"
    14	)
    15	
    16	// BUG(rsc): On OpenBSD, listening on the "tcp" network does not listen for
    17	// both IPv4 and IPv6 connections. This is due to the fact that IPv4 traffic
    18	// will not be routed to an IPv6 socket - two separate sockets are required
    19	// if both AFs are to be supported. See inet6(4) on OpenBSD for details.
    20	
    21	func sockaddrToTCP(sa syscall.Sockaddr) Addr {
    22		switch sa := sa.(type) {
    23		case *syscall.SockaddrInet4:
    24			return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port}
    25		case *syscall.SockaddrInet6:
    26			return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
    27		}
    28		return nil
    29	}
    30	
    31	func (a *TCPAddr) family() int {
    32		if a == nil || len(a.IP) <= IPv4len {
    33			return syscall.AF_INET
    34		}
    35		if a.IP.To4() != nil {
    36			return syscall.AF_INET
    37		}
    38		return syscall.AF_INET6
    39	}
    40	
    41	func (a *TCPAddr) isWildcard() bool {
    42		if a == nil || a.IP == nil {
    43			return true
    44		}
    45		return a.IP.IsUnspecified()
    46	}
    47	
    48	func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
    49		if a == nil {
    50			return nil, nil
    51		}
    52		return ipToSockaddr(family, a.IP, a.Port, a.Zone)
    53	}
    54	
    55	// TCPConn is an implementation of the Conn interface for TCP network
    56	// connections.
    57	type TCPConn struct {
    58		conn
    59	}
    60	
    61	func newTCPConn(fd *netFD) *TCPConn {
    62		c := &TCPConn{conn{fd}}
    63		c.SetNoDelay(true)
    64		return c
    65	}
    66	
    67	// ReadFrom implements the io.ReaderFrom ReadFrom method.
    68	func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
    69		if n, err, handled := sendFile(c.fd, r); handled {
    70			return n, err
    71		}
    72		return genericReadFrom(c, r)
    73	}
    74	
    75	// CloseRead shuts down the reading side of the TCP connection.
    76	// Most callers should just use Close.
    77	func (c *TCPConn) CloseRead() error {
    78		if !c.ok() {
    79			return syscall.EINVAL
    80		}
    81		return c.fd.closeRead()
    82	}
    83	
    84	// CloseWrite shuts down the writing side of the TCP connection.
    85	// Most callers should just use Close.
    86	func (c *TCPConn) CloseWrite() error {
    87		if !c.ok() {
    88			return syscall.EINVAL
    89		}
    90		return c.fd.closeWrite()
    91	}
    92	
    93	// SetLinger sets the behavior of Close on a connection which still
    94	// has data waiting to be sent or to be acknowledged.
    95	//
    96	// If sec < 0 (the default), the operating system finishes sending the
    97	// data in the background.
    98	//
    99	// If sec == 0, the operating system discards any unsent or
   100	// unacknowledged data.
   101	//
   102	// If sec > 0, the data is sent in the background as with sec < 0. On
   103	// some operating systems after sec seconds have elapsed any remaining
   104	// unsent data may be discarded.
   105	func (c *TCPConn) SetLinger(sec int) error {
   106		if !c.ok() {
   107			return syscall.EINVAL
   108		}
   109		return setLinger(c.fd, sec)
   110	}
   111	
   112	// SetKeepAlive sets whether the operating system should send
   113	// keepalive messages on the connection.
   114	func (c *TCPConn) SetKeepAlive(keepalive bool) error {
   115		if !c.ok() {
   116			return syscall.EINVAL
   117		}
   118		return setKeepAlive(c.fd, keepalive)
   119	}
   120	
   121	// SetKeepAlivePeriod sets period between keep alives.
   122	func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
   123		if !c.ok() {
   124			return syscall.EINVAL
   125		}
   126		return setKeepAlivePeriod(c.fd, d)
   127	}
   128	
   129	// SetNoDelay controls whether the operating system should delay
   130	// packet transmission in hopes of sending fewer packets (Nagle's
   131	// algorithm).  The default is true (no delay), meaning that data is
   132	// sent as soon as possible after a Write.
   133	func (c *TCPConn) SetNoDelay(noDelay bool) error {
   134		if !c.ok() {
   135			return syscall.EINVAL
   136		}
   137		return setNoDelay(c.fd, noDelay)
   138	}
   139	
   140	// DialTCP connects to the remote address raddr on the network net,
   141	// which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is
   142	// used as the local address for the connection.
   143	func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
   144		switch net {
   145		case "tcp", "tcp4", "tcp6":
   146		default:
   147			return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
   148		}
   149		if raddr == nil {
   150			return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress}
   151		}
   152		return dialTCP(net, laddr, raddr, noDeadline)
   153	}
   154	
   155	func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
   156		fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
   157	
   158		// TCP has a rarely used mechanism called a 'simultaneous connection' in
   159		// which Dial("tcp", addr1, addr2) run on the machine at addr1 can
   160		// connect to a simultaneous Dial("tcp", addr2, addr1) run on the machine
   161		// at addr2, without either machine executing Listen.  If laddr == nil,
   162		// it means we want the kernel to pick an appropriate originating local
   163		// address.  Some Linux kernels cycle blindly through a fixed range of
   164		// local ports, regardless of destination port.  If a kernel happens to
   165		// pick local port 50001 as the source for a Dial("tcp", "", "localhost:50001"),
   166		// then the Dial will succeed, having simultaneously connected to itself.
   167		// This can only happen when we are letting the kernel pick a port (laddr == nil)
   168		// and when there is no listener for the destination address.
   169		// It's hard to argue this is anything other than a kernel bug.  If we
   170		// see this happen, rather than expose the buggy effect to users, we
   171		// close the fd and try again.  If it happens twice more, we relent and
   172		// use the result.  See also:
   173		//	http://golang.org/issue/2690
   174		//	http://stackoverflow.com/questions/4949858/
   175		//
   176		// The opposite can also happen: if we ask the kernel to pick an appropriate
   177		// originating local address, sometimes it picks one that is already in use.
   178		// So if the error is EADDRNOTAVAIL, we have to try again too, just for
   179		// a different reason.
   180		//
   181		// The kernel socket code is no doubt enjoying watching us squirm.
   182		for i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(fd, err) || spuriousENOTAVAIL(err)); i++ {
   183			if err == nil {
   184				fd.Close()
   185			}
   186			fd, err = internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
   187		}
   188	
   189		if err != nil {
   190			return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
   191		}
   192		return newTCPConn(fd), nil
   193	}
   194	
   195	func selfConnect(fd *netFD, err error) bool {
   196		// If the connect failed, we clearly didn't connect to ourselves.
   197		if err != nil {
   198			return false
   199		}
   200	
   201		// The socket constructor can return an fd with raddr nil under certain
   202		// unknown conditions. The errors in the calls there to Getpeername
   203		// are discarded, but we can't catch the problem there because those
   204		// calls are sometimes legally erroneous with a "socket not connected".
   205		// Since this code (selfConnect) is already trying to work around
   206		// a problem, we make sure if this happens we recognize trouble and
   207		// ask the DialTCP routine to try again.
   208		// TODO: try to understand what's really going on.
   209		if fd.laddr == nil || fd.raddr == nil {
   210			return true
   211		}
   212		l := fd.laddr.(*TCPAddr)
   213		r := fd.raddr.(*TCPAddr)
   214		return l.Port == r.Port && l.IP.Equal(r.IP)
   215	}
   216	
   217	func spuriousENOTAVAIL(err error) bool {
   218		e, ok := err.(*OpError)
   219		return ok && e.Err == syscall.EADDRNOTAVAIL
   220	}
   221	
   222	// TCPListener is a TCP network listener.  Clients should typically
   223	// use variables of type Listener instead of assuming TCP.
   224	type TCPListener struct {
   225		fd *netFD
   226	}
   227	
   228	// AcceptTCP accepts the next incoming call and returns the new
   229	// connection.
   230	func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
   231		if l == nil || l.fd == nil {
   232			return nil, syscall.EINVAL
   233		}
   234		fd, err := l.fd.accept(sockaddrToTCP)
   235		if err != nil {
   236			return nil, err
   237		}
   238		return newTCPConn(fd), nil
   239	}
   240	
   241	// Accept implements the Accept method in the Listener interface; it
   242	// waits for the next call and returns a generic Conn.
   243	func (l *TCPListener) Accept() (Conn, error) {
   244		c, err := l.AcceptTCP()
   245		if err != nil {
   246			return nil, err
   247		}
   248		return c, nil
   249	}
   250	
   251	// Close stops listening on the TCP address.
   252	// Already Accepted connections are not closed.
   253	func (l *TCPListener) Close() error {
   254		if l == nil || l.fd == nil {
   255			return syscall.EINVAL
   256		}
   257		return l.fd.Close()
   258	}
   259	
   260	// Addr returns the listener's network address, a *TCPAddr.
   261	func (l *TCPListener) Addr() Addr { return l.fd.laddr }
   262	
   263	// SetDeadline sets the deadline associated with the listener.
   264	// A zero time value disables the deadline.
   265	func (l *TCPListener) SetDeadline(t time.Time) error {
   266		if l == nil || l.fd == nil {
   267			return syscall.EINVAL
   268		}
   269		return l.fd.setDeadline(t)
   270	}
   271	
   272	// File returns a copy of the underlying os.File, set to blocking
   273	// mode.  It is the caller's responsibility to close f when finished.
   274	// Closing l does not affect f, and closing f does not affect l.
   275	//
   276	// The returned os.File's file descriptor is different from the
   277	// connection's.  Attempting to change properties of the original
   278	// using this duplicate may or may not have the desired effect.
   279	func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() }
   280	
   281	// ListenTCP announces on the TCP address laddr and returns a TCP
   282	// listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
   283	// port of 0, ListenTCP will choose an available port.  The caller can
   284	// use the Addr method of TCPListener to retrieve the chosen address.
   285	func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
   286		switch net {
   287		case "tcp", "tcp4", "tcp6":
   288		default:
   289			return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
   290		}
   291		if laddr == nil {
   292			laddr = &TCPAddr{}
   293		}
   294		fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
   295		if err != nil {
   296			return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
   297		}
   298		return &TCPListener{fd}, nil
   299	}
   300	

View as plain text