Enhancing the boost::asio::connect() socket interface
(apologies if this should be on -developers...) The connect() interface provided by boost caters to most common use and through access to the socket, various options can be managed without much hindrance. But there's one situation that boost does not handle well - when it is desirable to specify the local address to bind to. Going back to C, the usual program flow in this situation is something like this: fd = socket() bind(fd, local ip address) connect(fd, remote ip address) As boost::asio::connect() closes an open socket passed to it before making the remote connection, it's not possible to pass connect() a prebaked socket. In fact the amount of code required to use boost when binding a socket to a local address is more complicated than simply not using boost. What I'd like the boost community to consider is extending boost::asio to provide one or more variants of connect() that allows for a local endpoint (whether or not as an iterator I'll leave to others to debate but this isn't necessary - and then there's the M*N behavior or paired to decide) to be supplied in addition to the remote endpoint. I suppose I'm open minded as to whether or not the local address is supplied as an Iterator/endpoint as an extra arg or whether connect() is adopted to take endpoint pairs. Thoughts?
On Sun, Sep 24, 2017 at 1:15 AM, martin doc via Boost-users
wrote: As boost::asio::connect() closes an open socket passed to it before making the remote connection, it's not possible to pass connect() a prebaked socket.
What makes you think that? My reading of the implementation is that the socket is only closed when: 1. The range of addresses passed to connect() has more than one element, and 2. The connection attempt for the first address fails. See: <https://github.com/boostorg/asio/blob/b002097359f246b7b1478775251dfb153ab3ff... You can avoid the socket closure by only attempting to connect to one address.
In fact the amount of code required to use boost when binding a socket to a local address is more complicated than simply not using boost.
That ignores all of the other benefits that Boost.Asio brings to the
table once the connection is made. And what happens when the
Networking-TS is merged into the standard? Will you just avoid using
the standard library?
Thanks
On Sun, Sep 24, 2017 at 1:15 AM, martin doc via Boost-users
(apologies if this should be on -developers...)
The connect() interface provided by boost caters to most common use and through access to the socket, various options can be managed without much hindrance. But there's one situation that boost does not handle well - when it is desirable to specify the local address to bind to.
Going back to C, the usual program flow in this situation is something like this:
fd = socket()
bind(fd, local ip address)
connect(fd, remote ip address)
As boost::asio::connect() closes an open socket passed to it before making the remote connection, it's not possible to pass connect() a prebaked socket. In fact the amount of code required to use boost when binding a socket to a local address is more complicated than simply not using boost.
What I'd like the boost community to consider is extending boost::asio to provide one or more variants of connect() that allows for a local endpoint (whether or not as an iterator I'll leave to others to debate but this isn't necessary - and then there's the M*N behavior or paired to decide) to be supplied in addition to the remote endpoint.
I suppose I'm open minded as to whether or not the local address is supplied as an Iterator/endpoint as an extra arg or whether connect() is adopted to take endpoint pairs.
Thoughts?
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org https://lists.boost.org/mailman/listinfo.cgi/boost-users
-- Follow me on GitHub: https://github.com/vinniefalco
On 24 September 2017 at 19:37, Vinnie Falco via Boost-users < boost-users@lists.boost.org> wrote:
On Sun, Sep 24, 2017 at 1:15 AM, martin doc via Boost-users < boost-users@lists.boost.org> wrote: As boost::asio::connect() closes an open socket passed to it before making the remote connection, it's not possible to pass connect() a prebaked socket.
What makes you think that? My reading of the implementation is that the socket is only closed when:
1. The range of addresses passed to connect() has more than one element, and 2. The connection attempt for the first address fails.
See:
<https://github.com/boostorg/asio/blob/b002097359f246b7b1478775251dfb 153ab3ff4b/include/boost/asio/impl/connect.hpp#L108
You can avoid the socket closure by only attempting to connect to one address.
Judging from that code, the socket is always closed before attempting a connect. The `s.close()` is right above the `s.connect()`. My guess is this is because the iterated endpoints may be using different protocols (TCP/IPv4 or TCP/IPv6 for example). Things become a bit hairy when you take that into account. You can't use a local TCP/IPv4 endpoint and connect to a TCP/IPv6 peer. What should `asio::connect` do in that case? Ignore the IPv6 endpoint? Or just not bind to a specific local endpoint? Or should you give it an iterator with at least one local endpoint per protocol in the iterated remote endpoints? And in that case, what should `asio::connect` do if there isn't a matching local endpoint? Return an error? Or not bind to a local endpoint? Personally I'm not sure which behaviour makes the most sense here. It seems like ASIO decided to sidestep the whole issue. You can still use `socket.connect()` directly with a single endpoint. Alternatively, you can wrap an already connected socket by passing the file descriptor to asio: http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/basic_str... http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/basic_str... Another option is to write your own `connect` function that does support binding to a local endpoint. If you have a nice way of dealing with different protocols in the iterated remote endpoints, you could even suggest your function for inclusion in ASIO. -- Maarten
As boost::asio::connect() closes an open socket passed to it before making the remote connection, it's not possible to pass connect() a prebaked socket.
I think the class template you're looking for is basic_raw_socket<>. http://www.boost.org/doc/libs/1_64_0/doc/html/boost_asio/reference/basic_raw... On 24 September 2017 at 21:02, Maarten de Vries via Boost-users < boost-users@lists.boost.org> wrote:
On 24 September 2017 at 19:37, Vinnie Falco via Boost-users < boost-users@lists.boost.org> wrote:
On Sun, Sep 24, 2017 at 1:15 AM, martin doc via Boost-users < boost-users@lists.boost.org> wrote: As boost::asio::connect() closes an open socket passed to it before making the remote connection, it's not possible to pass connect() a prebaked socket.
What makes you think that? My reading of the implementation is that the socket is only closed when:
1. The range of addresses passed to connect() has more than one element, and 2. The connection attempt for the first address fails.
See:
<https://github.com/boostorg/asio/blob/b002097359f246b7b1478 775251dfb153ab3ff4b/include/boost/asio/impl/connect.hpp#L108
You can avoid the socket closure by only attempting to connect to one address.
Judging from that code, the socket is always closed before attempting a connect. The `s.close()` is right above the `s.connect()`.
My guess is this is because the iterated endpoints may be using different protocols (TCP/IPv4 or TCP/IPv6 for example). Things become a bit hairy when you take that into account. You can't use a local TCP/IPv4 endpoint and connect to a TCP/IPv6 peer. What should `asio::connect` do in that case? Ignore the IPv6 endpoint? Or just not bind to a specific local endpoint? Or should you give it an iterator with at least one local endpoint per protocol in the iterated remote endpoints? And in that case, what should `asio::connect` do if there isn't a matching local endpoint? Return an error? Or not bind to a local endpoint? Personally I'm not sure which behaviour makes the most sense here. It seems like ASIO decided to sidestep the whole issue.
You can still use `socket.connect()` directly with a single endpoint. Alternatively, you can wrap an already connected socket by passing the file descriptor to asio:
http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/ reference/basic_stream_socket/basic_stream_socket/overload4.html http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/ reference/basic_stream_socket/assign.html Another option is to write your own `connect` function that does support binding to a local endpoint. If you have a nice way of dealing with different protocols in the iterated remote endpoints, you could even suggest your function for inclusion in ASIO.
-- Maarten
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org https://lists.boost.org/mailman/listinfo.cgi/boost-users
On 27/09/2017 19:03, Richard Hodges wrote:
As boost::asio::connect() closes an open socket passed to it before making the remote connection, it's not possible to pass connect() a prebaked socket.
I think the class template you're looking for is basic_raw_socket<>.
http://www.boost.org/doc/libs/1_64_0/doc/html/boost_asio/reference/basic_raw...
No, basic_raw_socket is for raw sockets, ie. non TCP/IP ones. Normally you'd use asio::ip::tcp::socket or asio::ip::udp::socket. They contain connect() methods which will connect to a single endpoint and will preserve a prior bind() call. If all you want is to connect to a single endpoint, then just s.bind()/s.connect() directly. Only the free function asio::connect() supports multiple endpoints and does the close()/connect() loop. If you want to support multiple endpoints and also bind, then you'll need to write your own close()/bind()/connect() loop similar to that. (There are also corresponding async_connect() methods, which should be preferred unless you really want to block the thread.)
participants (5)
-
Gavin Lambert
-
Maarten de Vries
-
martin doc
-
Richard Hodges
-
Vinnie Falco