c740be987b
Rather than matching a string, match a type. This is more robust considering future refactorings. We're confident the names did not change in _this_ refactoring because we're still testing the same strings in the tests. Part of https://github.com/ooni/probe/issues/2121
152 lines
3.4 KiB
Go
152 lines
3.4 KiB
Go
package tracex
|
|
|
|
//
|
|
// TCP and connected UDP sockets
|
|
//
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
|
)
|
|
|
|
// SaverDialer saves events occurring during the dial
|
|
type SaverDialer struct {
|
|
// Dialer is the underlying dialer,
|
|
Dialer model.Dialer
|
|
|
|
// Saver saves events.
|
|
Saver *Saver
|
|
}
|
|
|
|
// NewConnectObserver returns a DialerWrapper that observes the
|
|
// connect event. This function will return nil, which is a valid
|
|
// DialerWrapper for netxlite.WrapDialer, if Saver is nil.
|
|
func (s *Saver) NewConnectObserver() model.DialerWrapper {
|
|
if s == nil {
|
|
return nil // valid DialerWrapper according to netxlite's docs
|
|
}
|
|
return &saverDialerWrapper{
|
|
saver: s,
|
|
}
|
|
}
|
|
|
|
type saverDialerWrapper struct {
|
|
saver *Saver
|
|
}
|
|
|
|
var _ model.DialerWrapper = &saverDialerWrapper{}
|
|
|
|
func (w *saverDialerWrapper) WrapDialer(d model.Dialer) model.Dialer {
|
|
return &SaverDialer{
|
|
Dialer: d,
|
|
Saver: w.saver,
|
|
}
|
|
}
|
|
|
|
// DialContext implements Dialer.DialContext
|
|
func (d *SaverDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
start := time.Now()
|
|
conn, err := d.Dialer.DialContext(ctx, network, address)
|
|
stop := time.Now()
|
|
d.Saver.Write(&EventConnectOperation{&EventValue{
|
|
Address: address,
|
|
Duration: stop.Sub(start),
|
|
Err: err,
|
|
Proto: network,
|
|
Time: stop,
|
|
}})
|
|
return conn, err
|
|
}
|
|
|
|
func (d *SaverDialer) CloseIdleConnections() {
|
|
d.Dialer.CloseIdleConnections()
|
|
}
|
|
|
|
// SaverConnDialer wraps the returned connection such that we
|
|
// collect all the read/write events that occur.
|
|
type SaverConnDialer struct {
|
|
// Dialer is the underlying dialer
|
|
Dialer model.Dialer
|
|
|
|
// Saver saves events
|
|
Saver *Saver
|
|
}
|
|
|
|
// NewReadWriteObserver returns a DialerWrapper that observes the
|
|
// I/O events. This function will return nil, which is a valid
|
|
// DialerWrapper for netxlite.WrapDialer, if Saver is nil.
|
|
func (s *Saver) NewReadWriteObserver() model.DialerWrapper {
|
|
if s == nil {
|
|
return nil // valid DialerWrapper according to netxlite's docs
|
|
}
|
|
return &saverReadWriteWrapper{
|
|
saver: s,
|
|
}
|
|
}
|
|
|
|
type saverReadWriteWrapper struct {
|
|
saver *Saver
|
|
}
|
|
|
|
var _ model.DialerWrapper = &saverReadWriteWrapper{}
|
|
|
|
func (w *saverReadWriteWrapper) WrapDialer(d model.Dialer) model.Dialer {
|
|
return &SaverConnDialer{
|
|
Dialer: d,
|
|
Saver: w.saver,
|
|
}
|
|
}
|
|
|
|
// DialContext implements Dialer.DialContext
|
|
func (d *SaverConnDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
conn, err := d.Dialer.DialContext(ctx, network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &saverConn{saver: d.Saver, Conn: conn}, nil
|
|
}
|
|
|
|
func (d *SaverConnDialer) CloseIdleConnections() {
|
|
d.Dialer.CloseIdleConnections()
|
|
}
|
|
|
|
type saverConn struct {
|
|
net.Conn
|
|
saver *Saver
|
|
}
|
|
|
|
func (c *saverConn) Read(p []byte) (int, error) {
|
|
start := time.Now()
|
|
count, err := c.Conn.Read(p)
|
|
stop := time.Now()
|
|
c.saver.Write(&EventReadOperation{&EventValue{
|
|
Data: p[:count],
|
|
Duration: stop.Sub(start),
|
|
Err: err,
|
|
NumBytes: count,
|
|
Time: stop,
|
|
}})
|
|
return count, err
|
|
}
|
|
|
|
func (c *saverConn) Write(p []byte) (int, error) {
|
|
start := time.Now()
|
|
count, err := c.Conn.Write(p)
|
|
stop := time.Now()
|
|
c.saver.Write(&EventWriteOperation{&EventValue{
|
|
Data: p[:count],
|
|
Duration: stop.Sub(start),
|
|
Err: err,
|
|
NumBytes: count,
|
|
Time: stop,
|
|
}})
|
|
return count, err
|
|
}
|
|
|
|
var _ model.Dialer = &SaverDialer{}
|
|
var _ model.Dialer = &SaverConnDialer{}
|
|
var _ net.Conn = &saverConn{}
|