-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Added optional argument on which address to bind (socket). #678
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
Conversation
You've read the important comment that you've removed in IpAddress, right? And you have no problem with that? |
I think it might be good, if one could choose which IP to bind to, but the given implementation is probably not good enough as pointed out by @LaurentGomila. |
Yes, the obvious alternative to the default parameter would be a separate overload. Then, there is no need for the questionable |
Something like sf::TcpListener::listenAll(unsigned short port) would be the simplest solution. Or if we wanted to avoid breaking the current API, something like sf::TcpListener::listenOn(unsigned short port, const sf::IpAddress& address) since this is the less common use case. |
I would leave it as proposed: About that In the end I believe it would be best to use |
I'd use an overload and use that opportunity to provide the IP address first. To me it's very, very uncommon to provide the port before providing the IP, even if we're not talking about an URI. |
Why would you prefer a default parameter to an overload here? Default parameters make sense when they improve the expressiveness of the API, i.e. when the caller knows what value is used if he omits the argument. Here, the opposite is the case:
I would provide the IP address last, because it's a common idiom to move parameters that represent additions to other overloads to the end. I've also heard the expression "listen on a port" more often, and e.g. the Java ServerSocket constructor does it the same way. |
@Bromeon as you've stated in your first commend, separate overload would indeed be the simplest, which is something this library strives for. Refactor the current |
So... are there any remaining issues with this pull request? @bumbar1's revised version corresponds to what came out of the discussion and should be easy to review within a few minutes. Edit: Maybe renaming the ip parameter of listen to address would make more sense, but that's just me... |
Yes, it should be named "address". |
I've renamed parameter and updated \see reference. |
So... is there still anything preventing this pull request from being accepted and merged? |
The order (port, address) feels weird, everything else uses (address, port). But given that address is the optional parameter, it also makes sense in this order. So... I don't know, but I'm not fully satisfied with this API. Using IpAddress::None feels weird too, because you're supposed to bind to any address, not to none... It's correct because IpAddress::None internally equals ADDRESS_ANY, but it's very confusing from a user point of view. |
It might seem weird, but if you consider that we are on the "receiving end" of the connection, addresses (the port is also considered an address in the transport layer) are interpreted in reverse order of the sending side. If you ask me, both make little sense 😏. It would make more sense for the sender to connect using port first then address, since the TCP PDU has to be assembled before wrapping it inside an IP packet, which is where the address comes into play. If, theoretically, SFML would support multicast, the port would come first as well, and the function would naturally fit into that ordering. What I am trying to say is that there really isn't any convention that "makes sense". Just use whatever makes the most sense from a functional point of view. So, I don't see any issue with (port, address) to be honest.
Technically, you actually bind to no address i.e. you are not bound to a specific address, meaning incoming connections on interfaces regardless of the address(es) bound to them should be handled by the socket since it isn't bound to a specific address. Think of the address like a filter for the kernel. If there is no filter, you get everything. From that perspective, IpAddress::None is correct, and for me also "feels right". People who have gotten accustomed to other APIs might already be used to binding to no address to accept connections on all interfaces, and the people who come from a theoretical background would understand it anyway. |
Yes, but it's still inconsistent with the other functions. And you know that I don't like inconsistencies.
I guess it depends on the point of view. "Any" looks more correct to me, since the system is allowed to pick any network interface, not none. "Any" means "I don't care", which is exactly what happens. And at the BSD socket level, it's INADDR_ANY too, not INADDR_NONE. |
That's why I wanted Having |
Well... I guess listen could also take the address first then port. I would be willing to sacrifice the optional parameter last for the consistency with the rest of the API.
What about sf::IpAddress::All? :stuck_out_tongue: |
It's not only internal, code like this can exist: sf::IpAddress interface = sf::IpAddress::None; // <-- here
if (some_condition)
interface = sf::IpAddress(some_specific_ip);
socket.listen(port, interface);
I guess we need at least a third opinion then.
What about I know it's not our philisophy, but for the network module, I feel like differing slightly from the BSD socket API could be confusing for some people. |
Third overload would then be If so, beside adjusting comparison operators, to account for the new member, would there be anything else to add/modify? |
You mean second, right?
All except |
I thought three overloads would be |
Good point. In that case, (address, port) may indeed be the better order. Later, it would also be possible to rename the unary
Our intent is never to please everyone, and duplicating functionality for the sake of it just leads to a bloated and hard-to-understand API. |
An overload that only changes the order of arguments is the worst thing I've ever seen (fortunately I haven't seen it yet in a library :p). |
Ok, ok :p |
Is there a reason why
|
Because they didn't need to. So obviously this can be changed if they now need to access a new private member. But your example is wrong, any invalid address should have m_valid to false, not just default constructed ones. |
If Should |
I never said it was ;)
It would make sense, yes. |
Should |
We don't have to change anything in the public API, sf::IpAddress::None can still be used for invalid addresses, except that internally it would have the m_valid flag unset instead of using a special address value. |
What do all those functions do if they are passed an invalid address? Nothing (i.e. hide logic error)? Assertion? I'm talking about now, where we have no exceptions. |
This is a different problem, that already exists with the current code. |
Am I right in assuming that this PR isn't fully ready yet? |
Yes. |
What's the state of this PR? |
Why did you move the operators to members? That has nothing to do with the feature, and there's a good reason why binary operators are defined globally... |
Because they need access to |
You didn't consider that Also, if resolve() fails to find a valid address, you would still set m_valid to true in 2 constructors. I don't think this makes much sense... |
How should invalid and any address be represented with only 0 available? That's because |
Superseded by #850. |
Before, SFML bound
sf::TcpListener
to all available addresses internally. This change lets you specify to which address you'd like to bind (listen).Only been tested on Ubuntu 14.04 (clean rebuild).