udpPacketLoop listens for incoming UDP packets. See also the comment on Proxy.requestsSema.
(ctx context.Context, conn *net.UDPConn, reqSema syncutil.Semaphore)
| 83 | // |
| 84 | // See also the comment on Proxy.requestsSema. |
| 85 | func (p *Proxy) udpPacketLoop(ctx context.Context, conn *net.UDPConn, reqSema syncutil.Semaphore) { |
| 86 | p.logger.InfoContext(ctx, "entering udp listener loop", "addr", conn.LocalAddr()) |
| 87 | |
| 88 | b := make([]byte, dns.MaxMsgSize) |
| 89 | for p.isStarted() { |
| 90 | n, localIP, remoteAddr, err := proxynetutil.UDPRead(conn, b, p.udpOOBSize) |
| 91 | // The documentation says to handle the packet even if err occurs. |
| 92 | if n > 0 { |
| 93 | // Make a copy of all bytes because ReadFrom() will overwrite the |
| 94 | // contents of b on the next call. We need that contents to sustain |
| 95 | // the call because we're handling them in goroutines. |
| 96 | packet := make([]byte, n) |
| 97 | copy(packet, b) |
| 98 | |
| 99 | sErr := reqSema.Acquire(ctx) |
| 100 | if sErr != nil { |
| 101 | p.logger.ErrorContext( |
| 102 | ctx, |
| 103 | "acquiring semaphore", |
| 104 | "proto", ProtoUDP, |
| 105 | slogutil.KeyError, sErr, |
| 106 | ) |
| 107 | |
| 108 | break |
| 109 | } |
| 110 | go func() { |
| 111 | defer reqSema.Release() |
| 112 | |
| 113 | p.udpHandlePacket(ctx, packet, localIP, remoteAddr, conn) |
| 114 | }() |
| 115 | } |
| 116 | |
| 117 | if err != nil { |
| 118 | logUDPConnError(err, conn, p.logger) |
| 119 | |
| 120 | break |
| 121 | } |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | // logUDPConnError writes suitable log message for given err. |
| 126 | func logUDPConnError(err error, conn *net.UDPConn, l *slog.Logger) { |
no test coverage detected