Home | History | Annotate | Download | only in net
      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 package net
      6 
      7 import (
      8 	"io"
      9 	"os"
     10 	"syscall"
     11 	"time"
     12 )
     13 
     14 // TCPConn is an implementation of the Conn interface for TCP network
     15 // connections.
     16 type TCPConn struct {
     17 	conn
     18 }
     19 
     20 func newTCPConn(fd *netFD) *TCPConn {
     21 	return &TCPConn{conn{fd}}
     22 }
     23 
     24 // ReadFrom implements the io.ReaderFrom ReadFrom method.
     25 func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
     26 	n, err := genericReadFrom(c, r)
     27 	if err != nil && err != io.EOF {
     28 		err = &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
     29 	}
     30 	return n, err
     31 }
     32 
     33 // CloseRead shuts down the reading side of the TCP connection.
     34 // Most callers should just use Close.
     35 func (c *TCPConn) CloseRead() error {
     36 	if !c.ok() {
     37 		return syscall.EINVAL
     38 	}
     39 	err := c.fd.closeRead()
     40 	if err != nil {
     41 		err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
     42 	}
     43 	return err
     44 }
     45 
     46 // CloseWrite shuts down the writing side of the TCP connection.
     47 // Most callers should just use Close.
     48 func (c *TCPConn) CloseWrite() error {
     49 	if !c.ok() {
     50 		return syscall.EINVAL
     51 	}
     52 	err := c.fd.closeWrite()
     53 	if err != nil {
     54 		err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
     55 	}
     56 	return err
     57 }
     58 
     59 // SetLinger sets the behavior of Close on a connection which still
     60 // has data waiting to be sent or to be acknowledged.
     61 //
     62 // If sec < 0 (the default), the operating system finishes sending the
     63 // data in the background.
     64 //
     65 // If sec == 0, the operating system discards any unsent or
     66 // unacknowledged data.
     67 //
     68 // If sec > 0, the data is sent in the background as with sec < 0. On
     69 // some operating systems after sec seconds have elapsed any remaining
     70 // unsent data may be discarded.
     71 func (c *TCPConn) SetLinger(sec int) error {
     72 	return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
     73 }
     74 
     75 // SetKeepAlive sets whether the operating system should send
     76 // keepalive messages on the connection.
     77 func (c *TCPConn) SetKeepAlive(keepalive bool) error {
     78 	if !c.ok() {
     79 		return syscall.EPLAN9
     80 	}
     81 	if err := setKeepAlive(c.fd, keepalive); err != nil {
     82 		return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
     83 	}
     84 	return nil
     85 }
     86 
     87 // SetKeepAlivePeriod sets period between keep alives.
     88 func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
     89 	if !c.ok() {
     90 		return syscall.EPLAN9
     91 	}
     92 	if err := setKeepAlivePeriod(c.fd, d); err != nil {
     93 		return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
     94 	}
     95 	return nil
     96 }
     97 
     98 // SetNoDelay controls whether the operating system should delay
     99 // packet transmission in hopes of sending fewer packets (Nagle's
    100 // algorithm).  The default is true (no delay), meaning that data is
    101 // sent as soon as possible after a Write.
    102 func (c *TCPConn) SetNoDelay(noDelay bool) error {
    103 	return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
    104 }
    105 
    106 // DialTCP connects to the remote address raddr on the network net,
    107 // which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is
    108 // used as the local address for the connection.
    109 func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
    110 	return dialTCP(net, laddr, raddr, noDeadline)
    111 }
    112 
    113 func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
    114 	if !deadline.IsZero() {
    115 		panic("net.dialTCP: deadline not implemented on Plan 9")
    116 	}
    117 	switch net {
    118 	case "tcp", "tcp4", "tcp6":
    119 	default:
    120 		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
    121 	}
    122 	if raddr == nil {
    123 		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
    124 	}
    125 	fd, err := dialPlan9(net, laddr, raddr)
    126 	if err != nil {
    127 		return nil, err
    128 	}
    129 	return newTCPConn(fd), nil
    130 }
    131 
    132 // TCPListener is a TCP network listener.  Clients should typically
    133 // use variables of type Listener instead of assuming TCP.
    134 type TCPListener struct {
    135 	fd *netFD
    136 }
    137 
    138 // AcceptTCP accepts the next incoming call and returns the new
    139 // connection.
    140 func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
    141 	if l == nil || l.fd == nil || l.fd.ctl == nil {
    142 		return nil, syscall.EINVAL
    143 	}
    144 	fd, err := l.fd.acceptPlan9()
    145 	if err != nil {
    146 		return nil, err
    147 	}
    148 	return newTCPConn(fd), nil
    149 }
    150 
    151 // Accept implements the Accept method in the Listener interface; it
    152 // waits for the next call and returns a generic Conn.
    153 func (l *TCPListener) Accept() (Conn, error) {
    154 	if l == nil || l.fd == nil || l.fd.ctl == nil {
    155 		return nil, syscall.EINVAL
    156 	}
    157 	c, err := l.AcceptTCP()
    158 	if err != nil {
    159 		return nil, err
    160 	}
    161 	return c, nil
    162 }
    163 
    164 // Close stops listening on the TCP address.
    165 // Already Accepted connections are not closed.
    166 func (l *TCPListener) Close() error {
    167 	if l == nil || l.fd == nil || l.fd.ctl == nil {
    168 		return syscall.EINVAL
    169 	}
    170 	if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
    171 		l.fd.ctl.Close()
    172 		return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
    173 	}
    174 	err := l.fd.ctl.Close()
    175 	if err != nil {
    176 		err = &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
    177 	}
    178 	return err
    179 }
    180 
    181 // Addr returns the listener's network address, a *TCPAddr.
    182 // The Addr returned is shared by all invocations of Addr, so
    183 // do not modify it.
    184 func (l *TCPListener) Addr() Addr { return l.fd.laddr }
    185 
    186 // SetDeadline sets the deadline associated with the listener.
    187 // A zero time value disables the deadline.
    188 func (l *TCPListener) SetDeadline(t time.Time) error {
    189 	if l == nil || l.fd == nil || l.fd.ctl == nil {
    190 		return syscall.EINVAL
    191 	}
    192 	if err := l.fd.setDeadline(t); err != nil {
    193 		return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
    194 	}
    195 	return nil
    196 }
    197 
    198 // File returns a copy of the underlying os.File, set to blocking
    199 // mode.  It is the caller's responsibility to close f when finished.
    200 // Closing l does not affect f, and closing f does not affect l.
    201 //
    202 // The returned os.File's file descriptor is different from the
    203 // connection's.  Attempting to change properties of the original
    204 // using this duplicate may or may not have the desired effect.
    205 func (l *TCPListener) File() (f *os.File, err error) {
    206 	f, err = l.dup()
    207 	if err != nil {
    208 		err = &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
    209 	}
    210 	return
    211 }
    212 
    213 // ListenTCP announces on the TCP address laddr and returns a TCP
    214 // listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
    215 // port of 0, ListenTCP will choose an available port.  The caller can
    216 // use the Addr method of TCPListener to retrieve the chosen address.
    217 func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
    218 	switch net {
    219 	case "tcp", "tcp4", "tcp6":
    220 	default:
    221 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
    222 	}
    223 	if laddr == nil {
    224 		laddr = &TCPAddr{}
    225 	}
    226 	fd, err := listenPlan9(net, laddr)
    227 	if err != nil {
    228 		return nil, err
    229 	}
    230 	return &TCPListener{fd}, nil
    231 }
    232