Enhancing the boost::asio::connect() socket interface

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Enhancing the boost::asio::connect() socket interface

Boost - Users mailing list

(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
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Enhancing the boost::asio::connect() socket interface

Boost - Users mailing list
>On Sun, Sep 24, 2017 at 1:15 AM, martin doc via Boost-users <[hidden email]> 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/b002097359f246b7b1478775251dfb153ab3ff4b/include/boost/asio/impl/connect.hpp#L108

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
<[hidden email]> wrote:

> (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
> [hidden email]
> https://lists.boost.org/mailman/listinfo.cgi/boost-users



--
Follow me on GitHub: https://github.com/vinniefalco
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Enhancing the boost::asio::connect() socket interface

Boost - Users mailing list


On 24 September 2017 at 19:37, Vinnie Falco via Boost-users <[hidden email]> wrote:
>On Sun, Sep 24, 2017 at 1:15 AM, martin doc via Boost-users <[hidden email]> 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/b002097359f246b7b1478775251dfb153ab3ff4b/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:

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
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Enhancing the boost::asio::connect() socket interface

Boost - Users mailing list
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<>.



On 24 September 2017 at 21:02, Maarten de Vries via Boost-users <[hidden email]> wrote:


On 24 September 2017 at 19:37, Vinnie Falco via Boost-users <[hidden email]> wrote:
>On Sun, Sep 24, 2017 at 1:15 AM, martin doc via Boost-users <[hidden email]> 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/b002097359f246b7b1478775251dfb153ab3ff4b/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:

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
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users


_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Enhancing the boost::asio::connect() socket interface

Boost - Users mailing list
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_socket.html

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.)

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users