--- /dev/null
+# On macOS, docker does not support IPv6.
+
+FROM alpine
+
+RUN apk add go fuse bash
+
+RUN go install github.com/anacrolix/godo@v1
+RUN echo "$HOME"
+ENV PATH="/root/go/bin:$PATH"
+
+WORKDIR /src
+
+COPY . .
+
+ARG GOCACHE=/root/.cache/go-build
+ARG GOMODCACHE=/root/go/pkg/mod
+
+RUN --mount=type=cache,target=$GOCACHE \
+ --mount=type=cache,target=$GOMODCACHE \
+ go test -failfast ./...
+
+# Can't use fuse inside Docker? Asks for modprobe fuse.
+
+# RUN --mount=type=cache,target=$GOCACHE \
+# --mount=type=cache,target=$GOMODCACHE \
+# ./fs/test.sh
)
func TestBoltPieceCompletionClosedWhenClientClosed(t *testing.T) {
+ c := qt.New(t)
cfg := TestingConfig(t)
pc, err := storage.NewBoltPieceCompletion(cfg.DataDir)
require.NoError(t, err)
defer ci.Close()
cfg.DefaultStorage = ci
cl, err := NewClient(cfg)
- require.NoError(t, err)
+ c.Assert(err, qt.IsNil, qt.Commentf("%#v", err))
cl.Close()
// And again, https://github.com/anacrolix/torrent/issues/158
cl, err = NewClient(cfg)
}
}
- sockets, err := listenAll(cl.listenNetworks(), cl.config.ListenHost, cl.config.ListenPort, cl.firewallCallback, cl.logger)
+ builtinListenNetworks := cl.listenNetworks()
+ sockets, err := listenAll(
+ builtinListenNetworks,
+ cl.config.ListenHost,
+ cl.config.ListenPort,
+ cl.firewallCallback,
+ cl.logger,
+ )
if err != nil {
return
}
+ if len(sockets) == 0 && len(builtinListenNetworks) != 0 {
+ err = fmt.Errorf("no sockets created for networks %v", builtinListenNetworks)
+ return
+ }
// Check for panics.
cl.LocalPort()
}
func TestDhtInheritBlocklist(t *testing.T) {
+ c := qt.New(t)
ipl := iplist.New(nil)
require.NotNil(t, ipl)
cfg := TestingConfig(t)
assert.Equal(t, ipl, s.(AnacrolixDhtServerWrapper).Server.IPBlocklist())
numServers++
})
- assert.EqualValues(t, 2, numServers)
+ c.Assert(numServers, qt.Not(qt.Equals), 0)
}
// Check that stuff is merged in subsequent AddTorrentSpec for the same
expectedNet, givenNet, addr string, validIp4 bool,
) {
l, err := listenFunc(givenNet, addr)
+ if isUnsupportedNetworkError(err) {
+ return
+ }
require.NoError(t, err)
defer l.Close()
assert.EqualValues(t, expectedNet, l.Addr().Network())
require.NoError(t, err)
defer c.Close()
assert.EqualValues(t, network, c.RemoteAddr().Network())
- assert.Equal(t, valid4, missinggo.AddrIP(c.RemoteAddr()).To4() != nil)
+ assert.Equal(t, valid4, missinggo.AddrIP(c.RemoteAddr()).To4() == nil)
}
-func listenClosure(rawListenFunc func(string, string) (net.Listener, error), network, addr string) func() (net.Listener, error) {
+func listenClosure(
+ rawListenFunc func(string, string) (net.Listener, error),
+ network, addr string,
+) func() (net.Listener, error) {
return func() (net.Listener, error) {
return rawListenFunc(network, addr)
}
"tcp",
false,
dialClosure(net.Dial, "tcp"),
- listenClosure(net.Listen, "tcp6", "localhost:0"),
+ listenClosure(net.Listen, "tcp4", "localhost:0"),
)
}
import (
"context"
+ "errors"
+ "fmt"
+ g "github.com/anacrolix/generics"
"net"
+ "os"
"strconv"
"syscall"
"github.com/anacrolix/log"
"github.com/anacrolix/missinggo/perf"
"github.com/anacrolix/missinggo/v2"
- "github.com/pkg/errors"
)
type Listener interface {
NetworkDialer
}
-func listenAll(networks []network, getHost func(string) string, port int, f firewallCallback, logger log.Logger) ([]socket, error) {
+func listenAll(
+ networks []network,
+ getHost func(string) string,
+ port int,
+ f firewallCallback,
+ logger log.Logger,
+) ([]socket, error) {
if len(networks) == 0 {
return nil, nil
}
Host string
}
-func listenAllRetry(nahs []networkAndHost, port int, f firewallCallback, logger log.Logger) (ss []socket, retry bool, err error) {
- ss = make([]socket, 1, len(nahs))
- portStr := strconv.FormatInt(int64(port), 10)
- ss[0], err = listen(nahs[0].Network, net.JoinHostPort(nahs[0].Host, portStr), f, logger)
- if err != nil {
- return nil, false, errors.Wrap(err, "first listen")
+func isUnsupportedNetworkError(err error) bool {
+ var sysErr *os.SyscallError
+ //spewCfg := spew.NewDefaultConfig()
+ //spewCfg.ContinueOnMethod = true
+ //spewCfg.Dump(err)
+ if !errors.As(err, &sysErr) {
+ return false
}
+ //spewCfg.Dump(sysErr)
+ //spewCfg.Dump(sysErr.Err.Error())
+ // This might only be Linux specific.
+ return sysErr.Syscall == "bind" && sysErr.Err.Error() == "cannot assign requested address"
+}
+
+func listenAllRetry(
+ nahs []networkAndHost,
+ port int,
+ f firewallCallback,
+ logger log.Logger,
+) (ss []socket, retry bool, err error) {
+ // Close all sockets on error or retry.
defer func() {
if err != nil || retry {
for _, s := range ss {
ss = nil
}
}()
- portStr = strconv.FormatInt(int64(missinggo.AddrPort(ss[0].Addr())), 10)
- for _, nah := range nahs[1:] {
- s, err := listen(nah.Network, net.JoinHostPort(nah.Host, portStr), f, logger)
+ g.MakeSliceWithCap(&ss, len(nahs))
+ portStr := strconv.FormatInt(int64(port), 10)
+ for _, nah := range nahs {
+ var s socket
+ s, err = listen(nah.Network, net.JoinHostPort(nah.Host, portStr), f, logger)
if err != nil {
- return ss,
- missinggo.IsAddrInUse(err) && port == 0,
- errors.Wrap(err, "subsequent listen")
+ if isUnsupportedNetworkError(err) {
+ err = nil
+ continue
+ }
+ if len(ss) == 0 {
+ // First relative to a possibly dynamic port (0).
+ err = fmt.Errorf("first listen: %w", err)
+ } else {
+ err = fmt.Errorf("subsequent listen: %w", err)
+ }
+ retry = missinggo.IsAddrInUse(err) && port == 0
+ return
}
ss = append(ss, s)
+ portStr = strconv.FormatInt(int64(missinggo.AddrPort(ss[0].Addr())), 10)
}
return
}
func justOneNetwork(cc *torrent.ClientConfig) {
cc.DisableTCP = true
- cc.DisableIPv4 = true
+ cc.DisableIPv6 = true
}
func TestReceiveChunkStorageFailureSeederFastExtensionDisabled(t *testing.T) {
c.Assert(err, qt.IsNil)
defer pc.Close()
ccAddr := *cc.LocalAddr().(*net.UDPAddr)
- ccAddr.IP = net.IPv6loopback
+ ipAddrs, err := net.DefaultResolver.LookupIPAddr(context.Background(), "localhost")
+ c.Assert(err, qt.IsNil)
+ ccAddr.IP = ipAddrs[0].IP
+ ccAddr.Zone = ipAddrs[0].Zone
_, err = pc.WriteTo(make([]byte, 30), &ccAddr)
c.Assert(err, qt.IsNil)
}