-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Refactor ipfs p2p
#4929
Refactor ipfs p2p
#4929
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still needs race condition fixes in the registration logic but this is definitely looking better.
core/commands/p2p.go
Outdated
@@ -267,7 +267,7 @@ can transparently connect to a p2p service. | |||
return | |||
} | |||
|
|||
addr, peer, err := ParsePeerParam(req.Arguments()[0]) | |||
_, peer, err := ParsePeerParam(req.Arguments()[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Se should be adding this address to the peerstore (with a temporary TTL) if non-empty.
p2p/outbound.go
Outdated
} | ||
|
||
switch lnet { | ||
case "tcp", "tcp4", "tcp6": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to check this? I'd just listen and see if it fails.
p2p/outbound.go
Outdated
ctx, cancel := context.WithTimeout(l.ctx, time.Second*30) //TODO: configurable? | ||
defer cancel() | ||
|
||
err := l.p2p.peerHost.Connect(ctx, pstore.PeerInfo{ID: l.peer}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling NewStream
will implicitly call Connect
.
a6db350
to
768d2a0
Compare
core/commands/p2p.go
Outdated
ShortDescription: "Create and manage listener p2p endpoints", | ||
Tagline: "Forward connections to or from libp2p services", | ||
ShortDescription: ` | ||
Forward connections to <listen-address> to <target-address>. Protocol specifies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a 'from' missing in this sentence?
docs/experimental-features.md
Outdated
|
||
**On the "server" node:** | ||
|
||
First, start your application and have it listen on `$APP_PORT`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe clarify that this is a tcp socket being listened on, such as an ssh or http server.
docs/experimental-features.md
Outdated
Then, configure the p2p listener by running: | ||
|
||
```sh | ||
> ipfs p2p forward /kickass/1.0 /ipfs /ip4/127.0.0.1/tcp/$APP_PORT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whats the /ipfs in the middle for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the listen address. I could also make it accept the node peerid. I just wanted one command to handle forwarding in both directions.
It would be cleaner if we could specify this as a multiaddress. We'd need to define a multiaddr proto for string protocol names, probably something like /mux/protoName
. With that the command wouldn't have to accept magic strings, and the protocol name could get integrated with the address. Creating a libp2p service would look like
ipfs p2p forward /mux/someProto /ip4/127.0.0.1/tcp/$APP_PORT
And forwarding local connections to a service:
ipfs p2p forward /ip4/127.0.0.1/tcp/$APP_PORT /ipfs/QmPeer/mux/someProto
Does that make more sense?
edit: typo: s/ipfs p2p/ipfs p2p forward/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that makes sense... Its just a bit confusing. It would be nice to be able to make that simpler somehow. @Stebalien @Kubuxu @schomatis thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm getting the error Error: protocol name must be within '/p2p/' namespace
while trying to replicate the example (to better understand this conversation as I don't really know much about libp2p).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I get it now, changing /kickass/1.0
to /p2p/kickass/1.0
fixes that and the netcat example is working.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, should update that too (edit: done)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, going back to the original question, what seems confusing to me (again, I know nothing about libp2p so feel free to ignore this comment) is to have the p2p port in the front, which seems as if the forwarding is happening only at the p2p layer when in fact the message is routed through different layers (p2p-TCP).
If there were only two arguments (as suggested by @magik6k's solution that for me would be the ideal case) then the from-to relationship would become more evident, but if that isn't possible at the moment I would rather have two different commands that would clearly indicate to the user when the message is received at the p2p layer and routed to the TCP layer (and when the other way around); or at least I would reorganize the command arguments to group the p2p protocol with the p2p address.
p2p/local.go
Outdated
p2p *P2P | ||
id peer.ID | ||
|
||
proto string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe make this the protocol.ID
type?
p2p/listener.go
Outdated
// ListenerRegistry is a collection of local application proto listeners. | ||
type ListenerRegistry struct { | ||
Listeners map[listenerKey]Listener | ||
lk *sync.Mutex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why a pointer to a mutex?
core/commands/p2p.go
Outdated
Forward connections to <listen-address> to <target-address>. Protocol specifies | ||
the libp2p protocol to use. | ||
|
||
To create libp2p service listener, specify '/ipfs' as <listen-address> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To create a libp2p service listener
core/commands/p2p.go
Outdated
"ls": p2pListenerLsCmd, | ||
"open": p2pListenerListenCmd, | ||
"close": p2pListenerCloseCmd, | ||
//TODO: Do we really want/need implicit prefix? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on this?
Would it cause any restrictions or confusion, with or without them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It basically restricts one from communicating with libp2p services not in /p2p
namespace (so e.g. you can't use this to talk to other peers' bitswap which uses /ipfs/bitswap/1.1.0
as protocol name). The restriction was there before (probably put there by me), but now I'm not sure if we really want/need it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It probably makes sense to make the user always type /p2p/foo even if we restrict them to that namespace. That way, in the future, if we remove that restriction, we don't have to do anything weird.
docs/experimental-features.md
Outdated
|
||
First, configure the p2p dialer to forward all inbound connections on | ||
`127.0.0.1:SOME_PORT` to the listener behind `/p2p/kickass/1.0` on the server | ||
node. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, configure the p2p dialer to forward all inbound connections on
127.0.0.1:SOME_PORT
to the listener behind/p2p/kickass/1.0
on the server node.
It may be fine as is, but I wonder if this is more clear.
First, configure the client p2p dialer, so that it forwards all inbound connections on
127.0.0.1:SOME_PORT
to the server node listening on/p2p/kickass/1.0
.
core/commands/p2p.go
Outdated
}, | ||
Arguments: []cmdkit.Argument{ | ||
cmdkit.StringArg("protocol", true, false, "Protocol identifier."), | ||
cmdkit.StringArg("listen-address", true, false, "Listening endpoint"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing full stop
"Listening endpoint."
core/commands/p2p.go
Outdated
cmdkit.StringArg("Protocol", true, false, "Protocol identifier."), | ||
cmdkit.StringArg("BindAddress", false, false, "Address to listen for connection/s (default: /ip4/127.0.0.1/tcp/0)."), | ||
Options: []cmdkit.Option{ | ||
cmdkit.BoolOption("headers", "v", "Print table headers (HagndlerID, Protocol, Local, Remote)."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HagndlerID -> HandlerID
core/commands/ping.go
Outdated
@@ -182,9 +182,11 @@ func pingPeer(ctx context.Context, n *core.IpfsNode, pid peer.ID, numPings int) | |||
} | |||
|
|||
func ParsePeerParam(text string) (ma.Multiaddr, peer.ID, error) { | |||
// to be replaced with just multiaddr parsing, once ptp is a multiaddr protocol | |||
idx := strings.LastIndex(text, "/") | |||
idx := strings.LastIndex(text, "/ipfs/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a few instances of the literal string "/ipfs/"
in the package, would it be better to declare it as a named const?
e.g. peerPrefix
or something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we'd parse those as a multiaddr, but for that we'd need to define new multiaddr proto for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/ipfs is a multiaddr protocol. That comment may be old. Actually, I believe this entire function is old. Use ParseString
from the go-ipfs-addr package.
p2p/remote.go
Outdated
p2p *P2P | ||
|
||
// Application proto identifier. | ||
proto string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If protocol.ID
type is used in local, change must be made here too
p2p/local.go
Outdated
return l.p2p.peerHost.NewStream(l.ctx, l.peer, protocol.ID(l.proto)) | ||
} | ||
|
||
func (l *localListener) acceptConns() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in this PR, but there's opportunity for logging errors inside of here. Maybe later if a p2p log-subsystem is added.
@magik6k It would be great if you could write up a separate document/tutorial on using |
@magik6k cool, looking pretty good. Last thing I want (aside from getting approvals from @Kubuxu and one other) is a comment I can link to explaining how existing users can update their workflow to work with the changed API. Probably worth posting that comment here: #3994 and then updating my main comment to reflect these changes |
Rebased + Updated the comment and added a summary in #3994 (comment) |
ca4ca83
to
39f6ab2
Compare
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
61af105
to
0b575bc
Compare
Rebased |
p2p/remote.go
Outdated
} | ||
|
||
func (l *remoteListener) Close() error { | ||
_, err := l.p2p.ListenersP2P.Deregister(string(l.proto)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we're just registering by protocol, this is going to have that close race condition we discussed. That is, if I try to close a listener forwarding to a specific local address twice while someone else is trying to open a listener (to a different local address), I can close their listener.
I believe the correct fix is to just do everything inside the listener manager. That is, no listener handles, etc. Just add a Close(...)
method to the listener's object that takes the close "constraints" (protocol, localAddr, remoteAddr).
Does that make sense? This is what I meant by reducing some of the abstractions.
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
I've added |
🎉 I think this has received enough review (4) and we haven't changed the interfaces in most of this review so I'm going to go ahead and merge it. It's not too late to make changes but we should try to make them before the next release (in case anyone gets cold feet and wants to change this). |
Also, @magik6k: ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ |
Fixes #4895.
TODO:
ssh -L