Skip to content

Commit b7bd9f0

Browse files
authored
feat(netxlite): add (*Netx).ListenTCP (#1279)
This diff adds the ListenTCP function to the *Netx struct. With this addition, based on #1278, we can remove some techdebt inside the testingx package. This is yak shaving while trying to add support for testing socks5 in the context of ooni/probe#2531.
1 parent 95a766a commit b7bd9f0

File tree

6 files changed

+49
-10
lines changed

6 files changed

+49
-10
lines changed

internal/netemx/tlsproxy.go

-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ func (srv *tlsProxyServer) MustStart() {
7979
srv.logger,
8080
&netxlite.Netx{Underlying: &netxlite.NetemUnderlyingNetworkAdapter{UNet: srv.unet}},
8181
epnt,
82-
srv.unet,
8382
)
8483

8584
// track this server as something to close later

internal/netxlite/netx.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ package netxlite
55
// network operations using a custom model.UnderlyingNetwork.
66
//
77

8-
import "github.com/ooni/probe-cli/v3/internal/model"
8+
import (
9+
"net"
10+
11+
"github.com/ooni/probe-cli/v3/internal/model"
12+
)
913

1014
// Netx allows constructing netxlite data types using a specific [model.UnderlyingNetwork].
1115
type Netx struct {
@@ -20,3 +24,8 @@ var _ model.MeasuringNetwork = &Netx{}
2024
func (netx *Netx) maybeCustomUnderlyingNetwork() *MaybeCustomUnderlyingNetwork {
2125
return &MaybeCustomUnderlyingNetwork{netx.Underlying}
2226
}
27+
28+
// ListenTCP creates a new listening TCP socket using the given address.
29+
func (netx *Netx) ListenTCP(network string, addr *net.TCPAddr) (net.Listener, error) {
30+
return netx.maybeCustomUnderlyingNetwork().Get().ListenTCP(network, addr)
31+
}

internal/netxlite/netx_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"net"
66
"net/http"
7+
"sync"
78
"testing"
89

910
"github.com/apex/log"
@@ -117,3 +118,34 @@ func TestNetxWithNetem(t *testing.T) {
117118
}
118119
})
119120
}
121+
122+
// We generally do not listen here as part of other tests, since the listening
123+
// functionality is mainly only use for testingx. So, here's a specific test for that.
124+
func TestNetxListenTCP(t *testing.T) {
125+
netx := &Netx{Underlying: nil}
126+
127+
listener := runtimex.Try1(netx.ListenTCP("tcp", &net.TCPAddr{}))
128+
serverEndpoint := listener.Addr().String()
129+
130+
// listen in a background goroutine
131+
wg := &sync.WaitGroup{}
132+
wg.Add(1)
133+
go func() {
134+
conn := runtimex.Try1(listener.Accept())
135+
conn.Close()
136+
wg.Done()
137+
}()
138+
139+
// dial in a background goroutine
140+
wg.Add(1)
141+
go func() {
142+
ctx := context.Background()
143+
dialer := netx.NewDialerWithoutResolver(log.Log)
144+
conn := runtimex.Try1(dialer.DialContext(ctx, "tcp", serverEndpoint))
145+
conn.Close()
146+
wg.Done()
147+
}()
148+
149+
// wait for the goroutines to finish
150+
wg.Wait()
151+
}

internal/testingx/httptestx.go

+3
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func mustNewHTTPServer(
8989
X509CertPool: nil, // the default when not using TLS
9090
}
9191
baseURL := &url.URL{Host: listener.Addr().String()}
92+
9293
switch !tlsConfig.IsNone() {
9394
case true:
9495
baseURL.Scheme = "https"
@@ -97,10 +98,12 @@ func mustNewHTTPServer(
9798
srv.Config.TLSConfig = srv.TLS
9899
srv.X509CertPool = runtimex.Try1(tlsConfig.Unwrap().DefaultCertPool())
99100
go srv.Config.ServeTLS(listener, "", "") // using server.TLSConfig
101+
100102
default:
101103
baseURL.Scheme = "http"
102104
go srv.Config.Serve(listener)
103105
}
106+
104107
srv.URL = baseURL.String()
105108
return srv
106109
}

internal/testingx/tlssniproxy.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
// TLSSNIProxyNetx is how [TLSSNIProxy] views [*netxlite.Netx].
1818
type TLSSNIProxyNetx interface {
19+
ListenTCP(network string, addr *net.TCPAddr) (net.Listener, error)
1920
NewDialerWithResolver(dl model.DebugLogger, r model.Resolver, w ...model.DialerWrapper) model.Dialer
2021
NewStdlibResolver(logger model.DebugLogger) model.Resolver
2122
}
@@ -38,13 +39,10 @@ type TLSSNIProxy struct {
3839
wg *sync.WaitGroup
3940
}
4041

41-
// TODO(bassosimone): MustNewTLSSNIProxyEx prototype would be simpler if
42-
// netxlite.Netx was also able to create listening TCP connections
43-
4442
// MustNewTLSSNIProxyEx creates a new [*TLSSNIProxy].
4543
func MustNewTLSSNIProxyEx(
46-
logger model.Logger, netx TLSSNIProxyNetx, tcpAddr *net.TCPAddr, tcpListener TCPListener) *TLSSNIProxy {
47-
listener := runtimex.Try1(tcpListener.ListenTCP("tcp", tcpAddr))
44+
logger model.Logger, netx TLSSNIProxyNetx, tcpAddr *net.TCPAddr) *TLSSNIProxy {
45+
listener := runtimex.Try1(netx.ListenTCP("tcp", tcpAddr))
4846
proxy := &TLSSNIProxy{
4947
closeOnce: sync.Once{},
5048
listener: listener,

internal/testingx/tlssniproxy_test.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ func TestTLSSNIProxy(t *testing.T) {
3232
Underlying: nil, // use the network
3333
}
3434
tcpAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)}
35-
tcpListener := &testingx.TCPListenerStdlib{}
3635

37-
proxy := testingx.MustNewTLSSNIProxyEx(log.Log, netxProxy, tcpAddr, tcpListener)
36+
proxy := testingx.MustNewTLSSNIProxyEx(log.Log, netxProxy, tcpAddr)
3837
closers = append(closers, proxy)
3938

4039
netxClient := &netxlite.Netx{
@@ -75,7 +74,6 @@ func TestTLSSNIProxy(t *testing.T) {
7574
log.Log,
7675
&netxlite.Netx{Underlying: &netxlite.NetemUnderlyingNetworkAdapter{UNet: proxyStack}},
7776
&net.TCPAddr{IP: net.IPv4(10, 0, 0, 1), Port: 443},
78-
proxyStack,
7977
)
8078
closers = append(closers, proxy)
8179

0 commit comments

Comments
 (0)