src/pkg/net/tcpsock_posix.go - The Go Programming Language

Golang

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