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 5package net 6 7import ( 8 "context" 9 "internal/itoa" 10 "io" 11 "net/netip" 12 "os" 13 "syscall" 14 "time" 15) 16 17// BUG(mikio): On JS and Windows, the File method of TCPConn and 18// TCPListener is not implemented. 19 20// TCPAddr represents the address of a TCP end point. 21type TCPAddr struct { 22 IP IP 23 Port int 24 Zone string // IPv6 scoped addressing zone 25} 26 27// AddrPort returns the [TCPAddr] a as a [netip.AddrPort]. 28// 29// If a.Port does not fit in a uint16, it's silently truncated. 30// 31// If a is nil, a zero value is returned. 32func (a *TCPAddr) AddrPort() netip.AddrPort { 33 if a == nil { 34 return netip.AddrPort{} 35 } 36 na, _ := netip.AddrFromSlice(a.IP) 37 na = na.WithZone(a.Zone) 38 return netip.AddrPortFrom(na, uint16(a.Port)) 39} 40 41// Network returns the address's network name, "tcp". 42func (a *TCPAddr) Network() string { return "tcp" } 43 44func (a *TCPAddr) String() string { 45 if a == nil { 46 return "<nil>" 47 } 48 ip := ipEmptyString(a.IP) 49 if a.Zone != "" { 50 return JoinHostPort(ip+"%"+a.Zone, itoa.Itoa(a.Port)) 51 } 52 return JoinHostPort(ip, itoa.Itoa(a.Port)) 53} 54 55func (a *TCPAddr) isWildcard() bool { 56 if a == nil || a.IP == nil { 57 return true 58 } 59 return a.IP.IsUnspecified() 60} 61 62func (a *TCPAddr) opAddr() Addr { 63 if a == nil { 64 return nil 65 } 66 return a 67} 68 69// ResolveTCPAddr returns an address of TCP end point. 70// 71// The network must be a TCP network name. 72// 73// If the host in the address parameter is not a literal IP address or 74// the port is not a literal port number, ResolveTCPAddr resolves the 75// address to an address of TCP end point. 76// Otherwise, it parses the address as a pair of literal IP address 77// and port number. 78// The address parameter can use a host name, but this is not 79// recommended, because it will return at most one of the host name's 80// IP addresses. 81// 82// See func [Dial] for a description of the network and address 83// parameters. 84func ResolveTCPAddr(network, address string) (*TCPAddr, error) { 85 switch network { 86 case "tcp", "tcp4", "tcp6": 87 case "": // a hint wildcard for Go 1.0 undocumented behavior 88 network = "tcp" 89 default: 90 return nil, UnknownNetworkError(network) 91 } 92 addrs, err := DefaultResolver.internetAddrList(context.Background(), network, address) 93 if err != nil { 94 return nil, err 95 } 96 return addrs.forResolve(network, address).(*TCPAddr), nil 97} 98 99// TCPAddrFromAddrPort returns addr as a [TCPAddr]. If addr.IsValid() is false, 100// then the returned TCPAddr will contain a nil IP field, indicating an 101// address family-agnostic unspecified address. 102func TCPAddrFromAddrPort(addr netip.AddrPort) *TCPAddr { 103 return &TCPAddr{ 104 IP: addr.Addr().AsSlice(), 105 Zone: addr.Addr().Zone(), 106 Port: int(addr.Port()), 107 } 108} 109 110// TCPConn is an implementation of the [Conn] interface for TCP network 111// connections. 112type TCPConn struct { 113 conn 114} 115 116// KeepAliveConfig contains TCP keep-alive options. 117// 118// If the Idle, Interval, or Count fields are zero, a default value is chosen. 119// If a field is negative, the corresponding socket-level option will be left unchanged. 120// 121// Note that prior to Windows 10 version 1709, neither setting Idle and Interval 122// separately nor changing Count (which is usually 10) is supported. 123// Therefore, it's recommended to set both Idle and Interval to non-negative values 124// in conjunction with a -1 for Count on those old Windows if you intend to customize 125// the TCP keep-alive settings. 126// By contrast, if only one of Idle and Interval is set to a non-negative value, 127// the other will be set to the system default value, and ultimately, 128// set both Idle and Interval to negative values if you want to leave them unchanged. 129// 130// Note that Solaris and its derivatives do not support setting Interval to a non-negative value 131// and Count to a negative value, or vice-versa. 132type KeepAliveConfig struct { 133 // If Enable is true, keep-alive probes are enabled. 134 Enable bool 135 136 // Idle is the time that the connection must be idle before 137 // the first keep-alive probe is sent. 138 // If zero, a default value of 15 seconds is used. 139 Idle time.Duration 140 141 // Interval is the time between keep-alive probes. 142 // If zero, a default value of 15 seconds is used. 143 Interval time.Duration 144 145 // Count is the maximum number of keep-alive probes that 146 // can go unanswered before dropping a connection. 147 // If zero, a default value of 9 is used. 148 Count int 149} 150 151// SyscallConn returns a raw network connection. 152// This implements the [syscall.Conn] interface. 153func (c *TCPConn) SyscallConn() (syscall.RawConn, error) { 154 if !c.ok() { 155 return nil, syscall.EINVAL 156 } 157 return newRawConn(c.fd), nil 158} 159 160// ReadFrom implements the [io.ReaderFrom] ReadFrom method. 161func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) { 162 if !c.ok() { 163 return 0, syscall.EINVAL 164 } 165 n, err := c.readFrom(r) 166 if err != nil && err != io.EOF { 167 err = &OpError{Op: "readfrom", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 168 } 169 return n, err 170} 171 172// WriteTo implements the io.WriterTo WriteTo method. 173func (c *TCPConn) WriteTo(w io.Writer) (int64, error) { 174 if !c.ok() { 175 return 0, syscall.EINVAL 176 } 177 n, err := c.writeTo(w) 178 if err != nil && err != io.EOF { 179 err = &OpError{Op: "writeto", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 180 } 181 return n, err 182} 183 184// CloseRead shuts down the reading side of the TCP connection. 185// Most callers should just use Close. 186func (c *TCPConn) CloseRead() error { 187 if !c.ok() { 188 return syscall.EINVAL 189 } 190 if err := c.fd.closeRead(); err != nil { 191 return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 192 } 193 return nil 194} 195 196// CloseWrite shuts down the writing side of the TCP connection. 197// Most callers should just use Close. 198func (c *TCPConn) CloseWrite() error { 199 if !c.ok() { 200 return syscall.EINVAL 201 } 202 if err := c.fd.closeWrite(); err != nil { 203 return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 204 } 205 return nil 206} 207 208// SetLinger sets the behavior of Close on a connection which still 209// has data waiting to be sent or to be acknowledged. 210// 211// If sec < 0 (the default), the operating system finishes sending the 212// data in the background. 213// 214// If sec == 0, the operating system discards any unsent or 215// unacknowledged data. 216// 217// If sec > 0, the data is sent in the background as with sec < 0. 218// On some operating systems including Linux, this may cause Close to block 219// until all data has been sent or discarded. 220// On some operating systems after sec seconds have elapsed any remaining 221// unsent data may be discarded. 222func (c *TCPConn) SetLinger(sec int) error { 223 if !c.ok() { 224 return syscall.EINVAL 225 } 226 if err := setLinger(c.fd, sec); err != nil { 227 return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 228 } 229 return nil 230} 231 232// SetKeepAlive sets whether the operating system should send 233// keep-alive messages on the connection. 234func (c *TCPConn) SetKeepAlive(keepalive bool) error { 235 if !c.ok() { 236 return syscall.EINVAL 237 } 238 if err := setKeepAlive(c.fd, keepalive); err != nil { 239 return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 240 } 241 return nil 242} 243 244// SetKeepAlivePeriod sets the duration the connection needs to 245// remain idle before TCP starts sending keepalive probes. 246// 247// Note that calling this method on Windows prior to Windows 10 version 1709 248// will reset the KeepAliveInterval to the default system value, which is normally 1 second. 249func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error { 250 if !c.ok() { 251 return syscall.EINVAL 252 } 253 if err := setKeepAliveIdle(c.fd, d); err != nil { 254 return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 255 } 256 return nil 257} 258 259// SetNoDelay controls whether the operating system should delay 260// packet transmission in hopes of sending fewer packets (Nagle's 261// algorithm). The default is true (no delay), meaning that data is 262// sent as soon as possible after a Write. 263func (c *TCPConn) SetNoDelay(noDelay bool) error { 264 if !c.ok() { 265 return syscall.EINVAL 266 } 267 if err := setNoDelay(c.fd, noDelay); err != nil { 268 return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 269 } 270 return nil 271} 272 273// MultipathTCP reports whether the ongoing connection is using MPTCP. 274// 275// If Multipath TCP is not supported by the host, by the other peer or 276// intentionally / accidentally filtered out by a device in between, a 277// fallback to TCP will be done. This method does its best to check if 278// MPTCP is still being used or not. 279// 280// On Linux, more conditions are verified on kernels >= v5.16, improving 281// the results. 282func (c *TCPConn) MultipathTCP() (bool, error) { 283 if !c.ok() { 284 return false, syscall.EINVAL 285 } 286 return isUsingMultipathTCP(c.fd), nil 287} 288 289func newTCPConn(fd *netFD, keepAliveIdle time.Duration, keepAliveCfg KeepAliveConfig, preKeepAliveHook func(*netFD), keepAliveHook func(KeepAliveConfig)) *TCPConn { 290 setNoDelay(fd, true) 291 if !keepAliveCfg.Enable && keepAliveIdle >= 0 { 292 keepAliveCfg = KeepAliveConfig{ 293 Enable: true, 294 Idle: keepAliveIdle, 295 } 296 } 297 c := &TCPConn{conn{fd}} 298 if keepAliveCfg.Enable { 299 if preKeepAliveHook != nil { 300 preKeepAliveHook(fd) 301 } 302 c.SetKeepAliveConfig(keepAliveCfg) 303 if keepAliveHook != nil { 304 keepAliveHook(keepAliveCfg) 305 } 306 } 307 return c 308} 309 310// DialTCP acts like [Dial] for TCP networks. 311// 312// The network must be a TCP network name; see func Dial for details. 313// 314// If laddr is nil, a local address is automatically chosen. 315// If the IP field of raddr is nil or an unspecified IP address, the 316// local system is assumed. 317func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) { 318 switch network { 319 case "tcp", "tcp4", "tcp6": 320 default: 321 return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(network)} 322 } 323 if raddr == nil { 324 return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} 325 } 326 sd := &sysDialer{network: network, address: raddr.String()} 327 c, err := sd.dialTCP(context.Background(), laddr, raddr) 328 if err != nil { 329 return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} 330 } 331 return c, nil 332} 333 334// TCPListener is a TCP network listener. Clients should typically 335// use variables of type [Listener] instead of assuming TCP. 336type TCPListener struct { 337 fd *netFD 338 lc ListenConfig 339} 340 341// SyscallConn returns a raw network connection. 342// This implements the [syscall.Conn] interface. 343// 344// The returned RawConn only supports calling Control. Read and 345// Write return an error. 346func (l *TCPListener) SyscallConn() (syscall.RawConn, error) { 347 if !l.ok() { 348 return nil, syscall.EINVAL 349 } 350 return newRawListener(l.fd), nil 351} 352 353// AcceptTCP accepts the next incoming call and returns the new 354// connection. 355func (l *TCPListener) AcceptTCP() (*TCPConn, error) { 356 if !l.ok() { 357 return nil, syscall.EINVAL 358 } 359 c, err := l.accept() 360 if err != nil { 361 return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 362 } 363 return c, nil 364} 365 366// Accept implements the Accept method in the [Listener] interface; it 367// waits for the next call and returns a generic [Conn]. 368func (l *TCPListener) Accept() (Conn, error) { 369 if !l.ok() { 370 return nil, syscall.EINVAL 371 } 372 c, err := l.accept() 373 if err != nil { 374 return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 375 } 376 return c, nil 377} 378 379// Close stops listening on the TCP address. 380// Already Accepted connections are not closed. 381func (l *TCPListener) Close() error { 382 if !l.ok() { 383 return syscall.EINVAL 384 } 385 if err := l.close(); err != nil { 386 return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 387 } 388 return nil 389} 390 391// Addr returns the listener's network address, a [*TCPAddr]. 392// The Addr returned is shared by all invocations of Addr, so 393// do not modify it. 394func (l *TCPListener) Addr() Addr { return l.fd.laddr } 395 396// SetDeadline sets the deadline associated with the listener. 397// A zero time value disables the deadline. 398func (l *TCPListener) SetDeadline(t time.Time) error { 399 if !l.ok() { 400 return syscall.EINVAL 401 } 402 return l.fd.SetDeadline(t) 403} 404 405// File returns a copy of the underlying [os.File]. 406// It is the caller's responsibility to close f when finished. 407// Closing l does not affect f, and closing f does not affect l. 408// 409// The returned os.File's file descriptor is different from the 410// connection's. Attempting to change properties of the original 411// using this duplicate may or may not have the desired effect. 412func (l *TCPListener) File() (f *os.File, err error) { 413 if !l.ok() { 414 return nil, syscall.EINVAL 415 } 416 f, err = l.file() 417 if err != nil { 418 return nil, &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} 419 } 420 return 421} 422 423// ListenTCP acts like [Listen] for TCP networks. 424// 425// The network must be a TCP network name; see func Dial for details. 426// 427// If the IP field of laddr is nil or an unspecified IP address, 428// ListenTCP listens on all available unicast and anycast IP addresses 429// of the local system. 430// If the Port field of laddr is 0, a port number is automatically 431// chosen. 432func ListenTCP(network string, laddr *TCPAddr) (*TCPListener, error) { 433 switch network { 434 case "tcp", "tcp4", "tcp6": 435 default: 436 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(network)} 437 } 438 if laddr == nil { 439 laddr = &TCPAddr{} 440 } 441 sl := &sysListener{network: network, address: laddr.String()} 442 ln, err := sl.listenTCP(context.Background(), laddr) 443 if err != nil { 444 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err} 445 } 446 return ln, nil 447} 448 449// roundDurationUp rounds d to the next multiple of to. 450func roundDurationUp(d time.Duration, to time.Duration) time.Duration { 451 return (d + to - 1) / to 452} 453