Skip to content

Commit

Permalink
introduce a basic tracer
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Dec 3, 2024
1 parent b312bc5 commit 389940b
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 8 deletions.
29 changes: 21 additions & 8 deletions proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type Proxy struct {
// For more control over the UDP socket, use ProxyConnectedSocket.
// Applications may add custom header fields to the response header,
// but MUST NOT call WriteHeader on the http.ResponseWriter.
func (s *Proxy) Proxy(w http.ResponseWriter, r *Request) error {
func (s *Proxy) Proxy(w http.ResponseWriter, r *Request, tracer *Tracer) error {
if s.closed.Load() {
w.WriteHeader(http.StatusServiceUnavailable)
return net.ErrClosed
Expand All @@ -59,14 +59,14 @@ func (s *Proxy) Proxy(w http.ResponseWriter, r *Request) error {
}
defer conn.Close()

return s.ProxyConnectedSocket(w, r, conn)
return s.ProxyConnectedSocket(w, conn, tracer)
}

// ProxyConnectedSocket proxies a request on a connected UDP socket.
// Applications may add custom header fields to the response header,
// but MUST NOT call WriteHeader on the http.ResponseWriter.
// It closes the connection before returning.
func (s *Proxy) ProxyConnectedSocket(w http.ResponseWriter, _ *Request, conn *net.UDPConn) error {
func (s *Proxy) ProxyConnectedSocket(w http.ResponseWriter, conn *net.UDPConn, tracer *Tracer) error {
if s.closed.Load() {
conn.Close()
w.WriteHeader(http.StatusServiceUnavailable)
Expand All @@ -91,17 +91,23 @@ func (s *Proxy) ProxyConnectedSocket(w http.ResponseWriter, _ *Request, conn *ne
wg.Add(3)
go func() {
defer wg.Done()
if err := s.proxyConnSend(conn, str); err != nil {
if err := s.proxyConnSend(conn, str, tracer); err != nil {
log.Printf("proxying send side to %s failed: %v", conn.RemoteAddr(), err)
}
str.Close()
if tracer != nil && tracer.SendDirectionClosed != nil {
tracer.SendDirectionClosed()
}
}()
go func() {
defer wg.Done()
if err := s.proxyConnReceive(conn, str); err != nil && !s.closed.Load() {
if err := s.proxyConnReceive(conn, str, tracer); err != nil && !s.closed.Load() {
log.Printf("proxying receive side to %s failed: %v", conn.RemoteAddr(), err)
}
str.Close()
if tracer != nil && tracer.ReceiveDirectionClosed != nil {
tracer.ReceiveDirectionClosed()
}
}()
go func() {
defer wg.Done()
Expand All @@ -116,7 +122,7 @@ func (s *Proxy) ProxyConnectedSocket(w http.ResponseWriter, _ *Request, conn *ne
return nil
}

func (s *Proxy) proxyConnSend(conn *net.UDPConn, str http3.Stream) error {
func (s *Proxy) proxyConnSend(conn *net.UDPConn, str http3.Stream, tracer *Tracer) error {
for {
data, err := str.ReceiveDatagram(context.Background())
if err != nil {
Expand All @@ -130,13 +136,17 @@ func (s *Proxy) proxyConnSend(conn *net.UDPConn, str http3.Stream) error {
// Drop this datagram. We currently only support proxying of UDP payloads.
continue
}
if _, err := conn.Write(data[n:]); err != nil {
b := data[n:]
if _, err := conn.Write(b); err != nil {
return err
}
if tracer != nil && tracer.SentData != nil {
tracer.SentData(len(b))
}
}
}

func (s *Proxy) proxyConnReceive(conn *net.UDPConn, str http3.Stream) error {
func (s *Proxy) proxyConnReceive(conn *net.UDPConn, str http3.Stream, tracer *Tracer) error {
b := make([]byte, 1500)
for {
n, err := conn.Read(b)
Expand All @@ -149,6 +159,9 @@ func (s *Proxy) proxyConnReceive(conn *net.UDPConn, str http3.Stream) error {
if err := str.SendDatagram(data); err != nil {
return err
}
if tracer != nil && tracer.ReceivedData != nil {
tracer.ReceivedData(n)
}
}
}

Expand Down
13 changes: 13 additions & 0 deletions tracer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package masque

// A Tracer can be used to monitor the progress of a proxied connection.
type Tracer struct {
// SentData is called when data is sent towards the target.
SentData func(n int)
// SentDirectionClosed is called when the send direction (towards the target) is closed.
SendDirectionClosed func()
// ReceivedData is called when data is received from the target.
ReceivedData func(n int)
// ReceiveDirectionClosed is called when the receive direction (from the target) is closed.
ReceiveDirectionClosed func()
}

0 comments on commit 389940b

Please sign in to comment.