asio review -- IPV4/V6 issue

A group of folks here in Phoenix got together and had a little asio 'review party'. Before we had too many beers to be useful, there was one primary issue the group discussed that I'd like to bring to the list -- some minor stuff will go offlist to Christopher directly. As was discussed early on in the review asio doesn't currently support ipv6. However, going forward ipv6 support is critical for the "Phoenix Group". Given the current asio interfaces it seems clear that the extension will come in the form of another namespace -- presumably asio::ipv6. This means that client code will need to be modified to make the upgrade to ipv6. The need to modify code for ipv6 support was disliked by the group. It was the consensus of this group that it would be preferable to explore a solution that could support both ipv4 and ipv6 addresses seemlessly without changes to client code. Part of the rationale for this is that most applications don't directly configure the ip addresses in code, but rather read them from configurations. Hence it would be nice if the upgrade was as simple as swithching over the configuration. Thus the same compiled app could directly support ipv4 and ipv6. Thoughts, discussion? Jeff

On 12/30/05, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
A group of folks here in Phoenix got together and had a little asio 'review party'. Before we had too many beers to be useful, there was one primary issue the group discussed that I'd like to bring to the list -- some minor stuff will go offlist to Christopher directly.
As was discussed early on in the review asio doesn't currently support ipv6. However, going forward ipv6 support is critical for the "Phoenix Group". Given the current asio interfaces it seems clear that the extension will come in the form of another namespace -- presumably asio::ipv6. This means that client code will need to be modified to make the upgrade to ipv6. The need to modify code for ipv6 support was disliked by the group. It was the consensus of this group that it would be preferable to explore a solution that could support both ipv4 and ipv6 addresses seemlessly without changes to client code. Part of the rationale for this is that most applications don't directly configure the ip addresses in code, but rather read them from configurations. Hence it would be nice if the upgrade was as simple as swithching over the configuration. Thus the same compiled app could directly support ipv4 and ipv6.
Thoughts, discussion?
I agree. As I already stated it would be great to at least have a builtin utility function which connects a socket via hostname or ip string. -- Cory Nelson http://www.int64.org

Hi Jeff, --- Jeff Garland <jeff@crystalclearsoftware.com> wrote:
A group of folks here in Phoenix got together and had a little asio 'review party'.
Times must be tough to need asio as an excuse for beer ;)
As was discussed early on in the review asio doesn't currently support ipv6. However, going forward ipv6 support is critical for the "Phoenix Group". Given the current asio interfaces it seems clear that the extension will come in the form of another namespace -- presumably asio::ipv6. This means that client code will need to be modified to make the upgrade to ipv6. The need to modify code for ipv6 support was disliked by the group. It was the consensus of this group that it would be preferable to explore a solution that could support both ipv4 and ipv6 addresses seemlessly without changes to client code. Part of the rationale for this is that most applications don't directly configure the ip addresses in code, but rather read them from configurations. Hence it would be nice if the upgrade was as simple as swithching over the configuration. Thus the same compiled app could directly support ipv4 and ipv6.
Thoughts, discussion?
I must preface this by saying I have virtually no IPv6 experience, so feel free to jump in and contribute or correct details. In the current design I think this could be accomplished by adding a new asio::ip namespace that contains: - An address class that can contain either IPv4 or IPv6 host addresses, with functions for converting to and from strings (much as asio::ipv4::address does already). It includes a function that tells the type of the contained address. - A host class that contains host names and associated list of IPv4 and IPv6 addresses. - A host_resolver class that resolves host names into a list of both IPv4 and IPv6 addresses (if a host supports both). - A tcp class which is an implementation of the Protocol concept (as asio::ipv4::tcp is). However unlike asio::ipv4::tcp this one does not return constant values and does not have a default constructor. Instead it takes an enum indicating whether the protocol is for IPv4 or IPv6, and the values returned by its member functions vary accordingly. - A tcp::endpoint class that contains an address object and a port number. The protocol_type typedef for this object is for the asio::ip::tcp class. - The tcp::endpoint::protocol() member function returns a tcp object constructed for either IPv4 or IPv6 depending on the type of the address object that it contains. - A similar implementation of this for the udp class. Some examples: // Binding to an IPv4 localhost address using a string: asio::ip::address address("127.0.0.1"); asio::ip::endpoint endpoint(12345, address); asio::datagram_socket socket(demuxer); socket.open(endpoint.protocol()); socket.bind(endpoint); // Same as above using IPv6. asio::ip::address address("::1"); asio::ip::endpoint endpoint(12345, address); asio::datagram_socket socket(demuxer); socket.open(endpoint.protocol()); socket.bind(endpoint); // Host resolution and connection. asio::ip::host host; asio::ip::host_resolver host_resolver(demuxer); host_resolver.get_host_by_name(host, "foobar"); asio::ip::endpoint endpoint(12345, host.addresses(0)); asio::stream_socket socket(demuxer); socket.connect(endpoint); Assuming this works... - Is it worth keeping separate ipv4 and ipv6 namespaces? Some applications may want to explicitly specify one or the other. - How does this fit with Giovanni Deretta's suggestion of separate types for each protocol's socket? Does it mean having an asio::ip::tcp::socket type, for example? The issue is that the concrete protocol (IPv4 or IPv6) needs to be known before the socket object is opened. Cheers, Chris

Christopher Kohlhoff wrote:
- Is it worth keeping separate ipv4 and ipv6 namespaces? Some applications may want to explicitly specify one or the other.
You can consider it from the operating system upwards. In modern Windows and Unixes best practice is to use getaddrinfo and getnameinfo for translation to and from network and human address representation, and these calls work portably with IPv4 and IPv6 addresses today. Every function call for whom the network family is relevant receives this information at runtime, and not at compile time. (Like, say, wprintf is hardwired to the wchar_t character type.) So separating IPv4 and IPv6 into almost two separate libraries is not something the operating system forces or suggests. What kind of usability does it provide?
- How does this fit with Giovanni Deretta's suggestion of separate types for each protocol's socket? Does it mean having an asio::ip::tcp::socket type, for example? The issue is that the concrete protocol (IPv4 or IPv6) needs to be known before the socket object is opened.
Something like this? template <int FamilyT, int StyleT, int ProtocolT> class socket; It provides static knowledge of "family" and "style" that could be useful if you want to do some magic with the endless amount of flags and parameters for getsockopt and setsockopt specific to each, and gives us a neat default constructor. Otherwise, where would this information make a difference at compile time? Maybe validating generic address objects passed to connect or bind or whatever, or making getsockname and getpeername easier to use? Me, being a big fan of IOStreams, dismissed quickly this approach while trying to work with: // Lots of static structs to wrap all those ints template <typename CharT, typename TraitsT, typename FamilyT, typename StyleT, typename ProtocolT> class basic_socketstream; It's just too ugly. -- Pedro Lamarão Desenvolvimento Intersix Technologies S.A. SP: (55 11 3803-9300) RJ: (55 21 3852-3240) www.intersix.com.br Your Security is our Business

Hi Pedro, --- Pedro Lamarão <pedro.lamarao@intersix.com.br> wrote: <snip>
So separating IPv4 and IPv6 into almost two separate libraries is not something the operating system forces or suggests. What kind of usability does it provide?
I was thinking more in terms of the ability to directly manipulate addresses, endpoints etc for only one type. I.e. in applications where you do not want automatic runtime support for both IPv4 and IPv6. These applications shouldn't need to check the type of an address at runtime if compile-time checking is available. However I am asking the question of whether it is valuable to retain the separate types because I don't know whether such use cases do exist, or are common enough to warrant maintaining this support.
Something like this?
template <int FamilyT, int StyleT, int ProtocolT> class socket;
Actually the template parameter would be an implementation of the Protocol concept: class Protocol { public: int family() const; int type() const; int protocol() const; ... }; This still allows the protocol to be determined at runtime, if necessary (as it is to dynamically support both IPv4 and IPv6).
It provides static knowledge of "family" and "style" that could be useful if you want to do some magic with the endless amount of flags and parameters for getsockopt and setsockopt specific to each, and gives us a neat default constructor. Otherwise, where would this information make a difference at compile time? Maybe validating generic address objects passed to connect or bind or whatever, or making getsockname and getpeername easier to use?
Yep, these last reasons are the motivation for these changes. I.e. adding compile-time type safety in dealing with socket types.
Me, being a big fan of IOStreams, dismissed quickly this approach while trying to work with:
// Lots of static structs to wrap all those ints
template <typename CharT, typename TraitsT, typename FamilyT, typename StyleT, typename ProtocolT> class basic_socketstream;
It's just too ugly.
Yes :) However from the user's point of view, the changes I'm planning would look more like: ip::tcp::endpoint ep(1234, "::1"); ip::tcp::socket s(io_service); s.connect(ep); Cheers, Chris
participants (4)
-
Christopher Kohlhoff
-
Cory Nelson
-
Jeff Garland
-
Pedro Lamarão