-
Notifications
You must be signed in to change notification settings - Fork 0
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
cmd/bootnode, p2p: use an alternate port mapped to NAT #1
Conversation
Would you mind briefly checking this idea before writing the test script and detailing? @fjl |
LGTM |
p2p/server.go
Outdated
} | ||
|
||
// changePort changes the port number of localnode. | ||
func (srv *Server) changePort(protocol string, port uint16) error { |
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 still don't quite understand why you want to process port changes on the server main loop. You can just change the port on LocalNode
, it is safe for concurrent use.
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 vaguely imagined something like server.ChangePort()
, or rpc method net_changePort
...
But I can't come up with a clear scenario(+barely imagined, ports are not properly mapped, and don't want to wait until the next refresh (10 minutes)).
As you said, I want to change it to the following. Is my understanding correct?
// in Server nat refresh loop
for {
select {
case _, ok := <-srv.quit:
if !ok {
return
}
case <-refresh.C:
log.Trace("Refreshing port mapping")
p, err := natm.AddMapping(protocol, external, internal, name, mapTimeout)
if err != nil {
log.Debug("Couldn't add port mapping", "err", err)
} else {
if p != uint16(external) {
log.Debug("Already mapped port", external, "use alternative port", p)
log = newLogger(protocol, int(p), internal, natm)
external = int(p)
switch protocol {
case "tcp":
srv.localnode.Set(enr.TCP(external))
case "udp":
srv.localnode.SetFallbackUDP(external)
}
}
}
refresh.Reset(mapTimeout)
}
}
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.
Yes that looks better.
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.
Actually, the flow can be a bit simpler than what you have there. Whether or not AddMapping
returns a port that is equal to the local port, we can just always call Set
or SetFallbackUDP
on LocalNode
. Idempotent updates will simply be ignored.
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.
Good. I applied that.
Additionally, changed log.Trace message to remove duplicate code. 7adc65f
@fjl Thank you so much for your kind review. For the rest, I'll submit a PR to geth repo along with adding some test script and proceed. |
The purpose of that PR is efficient handling for NAT that return by allocating an alternate port if the requested port is already in use. So I changed the interface because I need to handle the port number returned from the method for AddPortMapping. I tried not to change the interface, but I couldn't solve it without using channels, and I wanted to avoid using channels because I thought it would be fatal if the caller didn't handle them properly.
The refresh process for NAT mapping is handled by the user himself. This allows free control over each calling module (bootnode, p2p.Server). In the current implementation, duplication of code doesn't seem too bad.