Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: migrate to netip #567

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open

*: migrate to netip #567

wants to merge 11 commits into from

Conversation

jzelinskie
Copy link
Member

@jzelinskie jzelinskie commented Apr 14, 2022

This change replaces net.IP usage with netip.AddrPort.
As a part of changing bittorrent.Peer to embed a netip.AddrPort, this introduces Peer.MarshalBinary() and replaces ad-hoc storage peer keys with this implementation.

Closes #540
Fixes #538

@jzelinskie jzelinskie marked this pull request as draft April 14, 2022 03:50
Copy link
Member

@mrd0ll4r mrd0ll4r left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I'm mostly okay with this. Something about the redis implementation seems odd, and I don't remember how exactly that was laid out.
Now that I think about it, wasn't there also some markdown doc about that, which should maybe be updated with the new redis keys?

bittorrent/bittorrent.go Outdated Show resolved Hide resolved
storage/redis/peer_store.go Show resolved Hide resolved
storage/redis/peer_store.go Show resolved Hide resolved
ct := ps.getClock()
addr := p.AddrPort.Addr()
sk := swarmKey(ih, true, addr)
ihKey := sk[0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe name this differently, took me a while to see that this holds information about the address family...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this confused me a bit too looking back. I'm open to suggestions because it's non obvious to me, haha.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe just af or addrFamily or something like that?
This is a bit weird, not sure what I was thinking back then. We store a modtime (ok) at a key like 4S12345... in a hashmap called 4. So the leading 4 in the swarm key is redundant here. It's not redundant for it's actual use to identify a hashmap, though...

So, we could remove one byte off that key, but meh.
The first byte is the address family. We could return that as a second value from swarmKey or maybe have a function to extract it from an IP. I think both of those would clear up some of the confusion here.

EDIT: Maybe we can even remove the leading two bytes? The second byte is S/L, but if we only use the address family hashmap for garbage collection, do we need to distinguish between seeder and leecher side for the modtime of a swarm?
I still don't have the full overview of what I was doing with this, tbh. Maybe I'll open an issue to look into it at some point in the future...

storage/redis/peer_store.go Outdated Show resolved Hide resolved
storage/redis/peer_store.go Outdated Show resolved Hide resolved
storage/redis/peer_store.go Outdated Show resolved Hide resolved
@mrd0ll4r
Copy link
Member

mrd0ll4r commented Apr 16, 2022 via email

@jzelinskie jzelinskie marked this pull request as ready for review April 16, 2022 18:06
@jzelinskie
Copy link
Member Author

I think this is good to go now @mrd0ll4r. I'd like to create some follow ups before I add too many changes to this one PR.

frontend/http/writer.go Outdated Show resolved Hide resolved
skip-pkg-cache: true
skip-build-cache: false
go-version: "^1.18"
- uses: "authzed/actions/gofumpt@main"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will steal your github actions for my personal stuff :)

Copy link
Member

@mrd0ll4r mrd0ll4r left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright. A few more small ones and one more relevant one about sanitization of scrapes.
The redis stuff is still unclear in my head. I hope the tests catch the bugs...

// String implements fmt.Stringer, returning the base16 encoded PeerID.
func (p PeerID) String() string { return fmt.Sprintf("%x", p[:]) }

// MarshalBinary returns a 20-byte string of the raw bytes of the ID.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Not a string

func (i InfoHash) RawString() string {
return string(i[:])
}
// MarshalBinary returns a 20-byte string of the raw bytes of the InfoHash.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

r.Peer.IP.AddressFamily = IPv6
} else {
r.AddrPort = netip.AddrPortFrom(r.AddrPort.Addr().Unmap(), r.AddrPort.Port())
if !r.AddrPort.Addr().IsValid() || r.AddrPort.Addr().IsUnspecified() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sanitization is missing for scrape requests! Maybe add that, since we now have a Peer in the scrape request, instead of just an address family.

@@ -317,7 +300,7 @@ func (t *Frontend) handleRequest(r Request, w ResponseWriter) (actionName string
return
}

WriteAnnounce(w, txID, resp, actionID == announceV6ActionID, req.IP.AddressFamily == bittorrent.IPv6)
WriteAnnounce(w, txID, resp, actionID == announceV6ActionID, r.IP.Unmap().Is6())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: This should already be Unmapped, from line 211 above. Maybe add a doc comment about that somewhere...

// There are twice the amount of shards specified by the user, the first
// half is dedicated to IPv4 swarms and the second half is dedicated to
// IPv6 swarms.
idx := binary.BigEndian.Uint32(infoHash[:4]) % (uint32(len(ps.shards)) / 2)
if af == bittorrent.IPv6 {
if addr.Is6() && !addr.Is4In6() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favor of removing these Is4In6 checks (in everything but the sanitization middleware and frontends, of course). What do you think?

select {
case <-ps.closed:
panic("attempted to interact with stopped memory store")
default:
}

resp.InfoHash = ih
shard := ps.shards[ps.shardIndex(ih, addressFamily)]
shard := ps.shards[ps.shardIndex(ih, p.AddrPort.Addr())]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this breaks if we don't have the Is4In6 check and no sanitization for scrapes.

ct := ps.getClock()
addr := p.AddrPort.Addr()
sk := swarmKey(ih, true, addr)
ihKey := sk[0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe just af or addrFamily or something like that?
This is a bit weird, not sure what I was thinking back then. We store a modtime (ok) at a key like 4S12345... in a hashmap called 4. So the leading 4 in the swarm key is redundant here. It's not redundant for it's actual use to identify a hashmap, though...

So, we could remove one byte off that key, but meh.
The first byte is the address family. We could return that as a second value from swarmKey or maybe have a function to extract it from an IP. I think both of those would clear up some of the confusion here.

EDIT: Maybe we can even remove the leading two bytes? The second byte is S/L, but if we only use the address family hashmap for garbage collection, do we need to distinguish between seeder and leecher side for the modtime of a swarm?
I still don't have the full overview of what I was doing with this, tbh. Maybe I'll open an issue to look into it at some point in the future...

@@ -581,38 +586,38 @@ func (ps *peerStore) AnnouncePeers(ih bittorrent.InfoHash, seeder bool, numWant

if seeder {
// Append leechers as possible.
for _, pk := range conLeechers {
for _, sk := range conLeechers {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer these to stay pk as in peerKey, since they are encoded peers.

benchHookList(b, hooks, req)
}

func benchHookListV6(b *testing.B, hooks hookList) {
req := &bittorrent.AnnounceRequest{Peer: bittorrent.Peer{IP: bittorrent.IP{IP: net.ParseIP("fc00::0001"), AddressFamily: bittorrent.IPv6}}}
req := &bittorrent.AnnounceRequest{Peer: bittorrent.Peer{
AddrPort: netip.AddrPortFrom(netip.MustParseAddr("fc00:0001"), 0),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

netip.MustParseAddr will panic here. You forgot second colon in ipv6 address.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Explore replacing net.IP with inet.af/netaddr.IP
3 participants