-
Notifications
You must be signed in to change notification settings - Fork 18
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
Use random ports for network client #124
base: master
Are you sure you want to change the base?
Use random ports for network client #124
Conversation
# Conflicts: # src/C4Network2IO.cpp
First of all, thank you for the effort, we appreciate it.
I am not convinced, but let’s focus on more important things for now.
In itself doing more work is fine, as long as there is no easily noticable difference.
Yes, simply a constant would be better (a static constexpr variable, not
That is correct ;) You are free and encouraged to modify C4NetIO directly.
As usual, I invite @Fulgen301 to join the discussion. |
First a big 😘 for caring about this issue! I have some remarks to the host fallback:
A host fallback would be the icing on the cake. But if you inform the user I would give him the option to abort the lobby (before registering the lobby to league.clonkspot.org because this causes other processes to run like the Discord-Bot or other watches). So like Please be aware, that almost every host is connected over a router with a firewall for IPv6. So we don't only have the network address translation table that we need to adjust for IPv4 (DNAT "port forwarding") but also a firewall for the nodes behind the SOHO-router for IPv6 (and IPv4). Therefore i would suggest the following message: |
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.
The logic is backwards - you check whether a port is available, and then create a C4NeIO
instance; this is a TOCTOU race condition, as the port may have been used by another application in the meantime. The correct way is to attempt to create the C4NetIO
instance and determine a new port to use if it fails - or do what @maxmitti said and ignore bind errors since the OS can already choose a random port.
{ | ||
uint16_t port; | ||
|
||
if (defaultPort == NULL) |
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.
Never use NULL
in C++ - defaultPort also isn't a pointer.
} | ||
} | ||
|
||
T *netIO = CreateNetIO(this->logger, name, io, port, thread); |
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.
Unnecessary this->
. Additionally, you should use const
as the variable isn't changed, and brace-initialization unless the variable's type is auto
:
T *netIO = CreateNetIO(this->logger, name, io, port, thread); | |
T *const netIO{CreateNetIO(logger, name, io, port, thread)}; |
std::uint16_t C4Network2IO::DiscoverFreePort(const uint16_t attempts) | ||
{ | ||
static constexpr uint16_t maxPort = 65535; | ||
uint16_t port = NULL; |
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.
As above. Also, we use std::
for types wherever possible.
uint16_t port = NULL; | |
std::uint16_t port{0}; |
|
||
std::uint16_t C4Network2IO::DiscoverFreePort(const uint16_t attempts) | ||
{ | ||
static constexpr uint16_t maxPort = 65535; |
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.
This is a constant and therefore should be spelled MaxPort
; otherwise, same as above.
return false; | ||
} | ||
|
||
std::uint16_t C4Network2IO::DiscoverFreePort(const uint16_t attempts) |
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.
Same as above.
static constexpr uint16_t maxPort = 65535; | ||
uint16_t port = NULL; | ||
|
||
for (uint16_t i = 0; i < attempts; ++i) |
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.
Same as above.
|
||
for (uint16_t i = 0; i < attempts; ++i) | ||
{ | ||
port = SafeRandom(maxPort); |
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.
This can return 0
, which isn't a valid port.
@@ -1248,6 +1264,43 @@ void C4Network2IO::SendConnPackets() | |||
} | |||
} | |||
|
|||
bool C4Network2IO::CheckPortAvailability(const uint16_t port) | |||
{ | |||
const auto pNetIO = std::make_unique<C4NetIOUDP>(); |
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.
You can't check whether a TCP port is available by attempting to bind a UDP socket.
See issue #48.
Concerns:
CreateSetupNetIO
sounds clear enough?Regarding 2, you would probably say "Then check for free ports only when initial CreateNetIO fails", well, the problem is, per my observation, a C4NetIO no longer appears to be usable once it fails to claim socket, perhaps we can pass a C4NetIO factory to the CreateSetupNetIO to create a new C4NetIO instance once it fails, but do we really need to overcomplicate here?