diff --git a/cmd/torrent/main.go b/cmd/torrent/main.go index bd5d6f7a..61fd2ab2 100644 --- a/cmd/torrent/main.go +++ b/cmd/torrent/main.go @@ -18,6 +18,7 @@ import ( "github.com/anacrolix/envpprof" "github.com/anacrolix/missinggo/v2" "github.com/anacrolix/torrent/bencode" + "github.com/anacrolix/torrent/version" "github.com/davecgh/go-spew/spew" "github.com/dustin/go-humanize" "golang.org/x/xerrors" @@ -164,8 +165,11 @@ var flags struct { *ListFilesCmd `arg:"subcommand:list-files"` *SpewBencodingCmd `arg:"subcommand:spew-bencoding"` *AnnounceCmd `arg:"subcommand:announce"` + *VersionCmd `arg:"subcommand:version"` } +type VersionCmd struct{} + type SpewBencodingCmd struct{} type DownloadCmd struct { @@ -268,6 +272,11 @@ func mainErr() error { spew.Dump(v) } return nil + case flags.VersionCmd != nil: + fmt.Printf("HTTP User-Agent: %q\n", version.DefaultHttpUserAgent) + fmt.Printf("Torrent client version: %q\n", version.DefaultExtendedHandshakeClientVersion) + fmt.Printf("Torrent version prefix: %q\n", version.DefaultBep20Prefix) + return nil default: p.Fail(fmt.Sprintf("unexpected subcommand: %v", p.Subcommand())) panic("unreachable") diff --git a/config.go b/config.go index 03d85c06..c7720a0d 100644 --- a/config.go +++ b/config.go @@ -9,8 +9,9 @@ import ( "github.com/anacrolix/dht/v2" "github.com/anacrolix/dht/v2/krpc" "github.com/anacrolix/log" - "github.com/anacrolix/missinggo/v2" "github.com/anacrolix/missinggo/expect" + "github.com/anacrolix/missinggo/v2" + "github.com/anacrolix/torrent/version" "golang.org/x/time/rate" "github.com/anacrolix/torrent/iplist" @@ -157,10 +158,10 @@ func (cfg *ClientConfig) SetListenAddr(addr string) *ClientConfig { func NewDefaultClientConfig() *ClientConfig { cc := &ClientConfig{ - HTTPUserAgent: "Go-Torrent/1.0", - ExtendedHandshakeClientVersion: "go.torrent dev 20181121", - Bep20: "-GT0002-", - UpnpID: "anacrolix/torrent", + HTTPUserAgent: version.DefaultHttpUserAgent, + ExtendedHandshakeClientVersion: version.DefaultExtendedHandshakeClientVersion, + Bep20: version.DefaultBep20Prefix, + UpnpID: version.DefaultUpnpId, NominalDialTimeout: 20 * time.Second, MinDialTimeout: 3 * time.Second, EstablishedConnsPerTorrent: 50, diff --git a/tracker/http/http.go b/tracker/http/http.go index c4f2fac4..15306ca9 100644 --- a/tracker/http/http.go +++ b/tracker/http/http.go @@ -16,6 +16,7 @@ import ( "github.com/anacrolix/torrent/bencode" "github.com/anacrolix/torrent/tracker/shared" "github.com/anacrolix/torrent/tracker/udp" + "github.com/anacrolix/torrent/version" ) var vars = expvar.NewMap("tracker/http") @@ -76,7 +77,13 @@ func (cl Client) Announce(ctx context.Context, ar AnnounceRequest, opt AnnounceO _url := httptoo.CopyURL(cl.url_) setAnnounceParams(_url, &ar, opt) req, err := http.NewRequestWithContext(ctx, http.MethodGet, _url.String(), nil) - req.Header.Set("User-Agent", opt.UserAgent) + userAgent := opt.UserAgent + if userAgent == "" { + userAgent = version.DefaultHttpUserAgent + } + if userAgent != "" { + req.Header.Set("User-Agent", userAgent) + } req.Host = opt.HostHeader resp, err := cl.hc.Do(req) if err != nil { diff --git a/version/version.go b/version/version.go new file mode 100644 index 00000000..3d3ae550 --- /dev/null +++ b/version/version.go @@ -0,0 +1,58 @@ +// Package version provides default versions, user-agents etc. for client identification. +package version + +import ( + "fmt" + "reflect" + "runtime/debug" +) + +var ( + DefaultExtendedHandshakeClientVersion string + // This should be updated when client behaviour changes in a way that other peers could care + // about. + DefaultBep20Prefix = "-GT0003-" + DefaultHttpUserAgent string + DefaultUpnpId string +) + +func init() { + const ( + longNamespace = "anacrolix" + longPackageName = "torrent" + ) + type Newtype struct{} + var newtype Newtype + thisPkg := reflect.TypeOf(newtype).PkgPath() + var ( + mainPath = "unknown" + mainVersion = "unknown" + torrentVersion = "unknown" + ) + if buildInfo, ok := debug.ReadBuildInfo(); ok { + mainPath = buildInfo.Main.Path + mainVersion = buildInfo.Main.Version + // Note that if the main module is the same as this module, we get a version of "(devel)". + for _, dep := range append(buildInfo.Deps, &buildInfo.Main) { + if dep.Path == thisPkg { + torrentVersion = dep.Version + } + } + } + DefaultExtendedHandshakeClientVersion = fmt.Sprintf( + "%v %v (%v/%v %v)", + mainPath, + mainVersion, + longNamespace, + longPackageName, + torrentVersion, + ) + DefaultUpnpId = fmt.Sprintf("%v %v", mainPath, mainVersion) + // Per https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent#library_and_net_tool_ua_strings + DefaultHttpUserAgent = fmt.Sprintf( + "%v-%v/%v", + longNamespace, + longPackageName, + torrentVersion, + ) +}