Repository: moby/moby
File: cmd/docker-proxy/udp_proxy_linux.go (Go)

Code before:
	if proxy.ipVer == ip4 {
		cm := &ipv4.ControlMessage{Src: serverAddr}
		oob = cm.Marshal()
	} else {
		cm := &ipv6.ControlMessage{Src: serverAddr}
		oob = cm.Marshal()
	}

	readBuf := make([]byte, UDPBufSize)
	for {
		cte.conn.SetReadDeadline(time.Now().Add(proxy.connTrackTimeout))
	again:
		read, err := cte.conn.Read(readBuf)
		if err != nil {
			if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
				// This will happen if the last write failed
				// (e.g: nothing is actually listening on the
				// proxied port on the container), ignore it
				// and continue until DefaultConnTrackTimeout
				// expires:
				goto again
			}
			// If the UDP connection is one-sided (i.e. the backend never sends
			// replies), the connTrackEntry should not be GC'd until no writes
			// happen for proxy.connTrackTimeout.
			if errors.Is(err, os.ErrDeadlineExceeded) && cte.lastWrite() < proxy.connTrackTimeout {
				continue
			}
			return
		}
		for i := 0; i != read; {
			written, _, err := proxy.listener.WriteMsgUDP(readBuf[i:read], oob, clientAddr)
			if err != nil {
				return
			}
			i += written
		}
	}
}

// Run starts forwarding the traffic using UDP.
func (proxy *UDPProxy) Run() {
	readBuf := make([]byte, UDPBufSize)
	var oob []byte
	if proxy.ipVer == ip4 {
		oob = ipv4.NewControlMessage(ipv4.FlagDst)
	} else {
		oob = ipv6.NewControlMessage(ipv6.FlagDst)
	}

	for {

Review comment (suggestion):
big nit: `lastWrite` sounds more like it would return a timestamp instead of duration.

Moving the `time.Since` out of the `lastWrite` would read a little bit nicer:
```suggestion
			if errors.Is(err, os.ErrDeadlineExceeded) && time.Since(cte.lastWrite()) < proxy.connTrackTimeout {
```

Code after:
	}()

	var oob []byte
	if proxy.ipVer == ip4 {
		cm := &ipv4.ControlMessage{Src: serverAddr}
		oob = cm.Marshal()
	} else {
		cm := &ipv6.ControlMessage{Src: serverAddr}
		oob = cm.Marshal()
	}

	readBuf := make([]byte, UDPBufSize)
	for {
		cte.conn.SetReadDeadline(time.Now().Add(proxy.connTrackTimeout))
	again:
		read, err := cte.conn.Read(readBuf)
		if err != nil {
			if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
				// This will happen if the last write failed
				// (e.g: nothing is actually listening on the
				// proxied port on the container), ignore it
				// and continue until DefaultConnTrackTimeout
				// expires:
				goto again
			}
			// If the UDP connection is one-sided (i.e. the backend never sends
			// replies), the connTrackEntry should not be GC'd until no writes
			// happen for proxy.connTrackTimeout.
			//
			// Since the ReadDeadline is set to proxy.connTrackTimeout, in such
			// case, the connTrackEntry will be GC'd at most after 2 * proxy.connTrackTimeout.
			if errors.Is(err, os.ErrDeadlineExceeded) && time.Since(cte.lastWrite()) < proxy.connTrackTimeout {
				continue
			}
			return
		}
		for i := 0; i != read; {
			written, _, err := proxy.listener.WriteMsgUDP(readBuf[i:read], oob, clientAddr)
			if err != nil {
				return
			}
			i += written
		}
	}
}

// Run starts forwarding the traffic using UDP.
func (proxy *UDPProxy) Run() {
	readBuf := make([]byte, UDPBufSize)
	var oob []byte
	if proxy.ipVer == ip4 {