boost::asio::read() gets stuck when there's no internet

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

boost::asio::read() gets stuck when there's no internet

Boost - Users mailing list
In TgBot library i use under MSVC++, in tgbot/net/BoostHttpOnlySslClient.cpp,
a call to boost::asio::read() does not return when internet is disconnected for a few minutes.

I would appreciate any help to get this resolved, i.e. for the read function to return if it fails after some timeout has passed

the code block in the tgbot/net/BoostHttpOnlySslClient.cpp file:

[code]
string BoostHttpOnlySslClient::makeRequest(const Url& url, const vector<HttpReqArg>& args) const {
    tcp::resolver resolver(_ioService);
    tcp::resolver::query query(url.host, "443");

    ssl::context context(ssl::context::tlsv12_client);
    context.set_default_verify_paths();
    ssl::stream<tcp::socket> socket(_ioService, context);
    connect(socket.lowest_layer(), resolver.resolve(query));

    #ifdef TGBOT_DISABLE_NAGLES_ALGORITHM
    socket.lowest_layer().set_option(tcp::no_delay(true));
    #endif //TGBOT_DISABLE_NAGLES_ALGORITHM
    #ifdef TGBOT_CHANGE_SOCKET_BUFFER_SIZE
    #if _arm64 || _WIN64 || __amd64__ || __x86_64__ || __MINGW64__ || __aarch64__ || __powerpc64__
    socket.lowest_layer().set_option(socket_base::send_buffer_size(65536));
    socket.lowest_layer().set_option(socket_base::receive_buffer_size(65536));
    #else //for 32-bit
    socket.lowest_layer().set_option(socket_base::send_buffer_size(32768));
    socket.lowest_layer().set_option(socket_base::receive_buffer_size(32768));
    #endif //Processor architecture
    #endif //TGBOT_CHANGE_SOCKET_BUFFER_SIZE
    socket.set_verify_mode(ssl::verify_none);
    socket.set_verify_callback(ssl::rfc2818_verification(url.host));

    socket.handshake(ssl::stream<tcp::socket>::client);

    string requestText = _httpParser.generateRequest(url, args, false);
    write(socket, buffer(requestText.c_str(), requestText.length()));

    string response;

    #ifdef TGBOT_CHANGE_READ_BUFFER_SIZE
    #if _M_ARM64 || _WIN64 || __amd64__ || __x86_64__ || __MINGW64__ || __aarch64__ || __powerpc64__
    char buff[65536];
    #else //for 32-bit
    char buff[32768];
    #endif //Processor architecture
    #else
    char buff[1024];
    #endif //TGBOT_CHANGE_READ_BUFFER_SIZE

    boost::system::error_code error;
    while (!error) {
        std::size_t bytes = read(socket, buffer(buff), error);
        response += string(buff, bytes);
    }

    return _httpParser.extractBody(response);
}
[/code]

Thankyou in advance😀🙏

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

Re: boost::asio::read() gets stuck when there's no internet

Boost - Users mailing list
The TCP/IP protocol was designed to work over unreliable networks, including sections that hop over radio links and dial-up telephone lines.

In a nutshell, the way the internet works is that packets are transmitted and it is assumed that they may or may not arrive at some time in the future. There are timeouts built in, but they are longer than you would probably want, on account of all the unreliable dial-ups between you and the other peer.

Therefore, to involve a timeout you need to run a timer in parallel with the send/receive operation and cancel the operation if the timeout occurs before the operation has completed.

This is easier with asio's async interface, but you can still do it with the synchronous interface by using SIGALM (or equivalent).

The relevant voodoo is documented here for linux:



On Fri, 19 Feb 2021 at 17:52, Child OfGod via Boost-users <[hidden email]> wrote:
In TgBot library i use under MSVC++, in tgbot/net/BoostHttpOnlySslClient.cpp,
a call to boost::asio::read() does not return when internet is disconnected for a few minutes.

I would appreciate any help to get this resolved, i.e. for the read function to return if it fails after some timeout has passed

the code block in the tgbot/net/BoostHttpOnlySslClient.cpp file:

[code]
string BoostHttpOnlySslClient::makeRequest(const Url& url, const vector<HttpReqArg>& args) const {
    tcp::resolver resolver(_ioService);
    tcp::resolver::query query(url.host, "443");

    ssl::context context(ssl::context::tlsv12_client);
    context.set_default_verify_paths();
    ssl::stream<tcp::socket> socket(_ioService, context);
    connect(socket.lowest_layer(), resolver.resolve(query));

    #ifdef TGBOT_DISABLE_NAGLES_ALGORITHM
    socket.lowest_layer().set_option(tcp::no_delay(true));
    #endif //TGBOT_DISABLE_NAGLES_ALGORITHM
    #ifdef TGBOT_CHANGE_SOCKET_BUFFER_SIZE
    #if _arm64 || _WIN64 || __amd64__ || __x86_64__ || __MINGW64__ || __aarch64__ || __powerpc64__
    socket.lowest_layer().set_option(socket_base::send_buffer_size(65536));
    socket.lowest_layer().set_option(socket_base::receive_buffer_size(65536));
    #else //for 32-bit
    socket.lowest_layer().set_option(socket_base::send_buffer_size(32768));
    socket.lowest_layer().set_option(socket_base::receive_buffer_size(32768));
    #endif //Processor architecture
    #endif //TGBOT_CHANGE_SOCKET_BUFFER_SIZE
    socket.set_verify_mode(ssl::verify_none);
    socket.set_verify_callback(ssl::rfc2818_verification(url.host));

    socket.handshake(ssl::stream<tcp::socket>::client);

    string requestText = _httpParser.generateRequest(url, args, false);
    write(socket, buffer(requestText.c_str(), requestText.length()));

    string response;

    #ifdef TGBOT_CHANGE_READ_BUFFER_SIZE
    #if _M_ARM64 || _WIN64 || __amd64__ || __x86_64__ || __MINGW64__ || __aarch64__ || __powerpc64__
    char buff[65536];
    #else //for 32-bit
    char buff[32768];
    #endif //Processor architecture
    #else
    char buff[1024];
    #endif //TGBOT_CHANGE_READ_BUFFER_SIZE

    boost::system::error_code error;
    while (!error) {
        std::size_t bytes = read(socket, buffer(buff), error);
        response += string(buff, bytes);
    }

    return _httpParser.extractBody(response);
}
[/code]

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


--
Richard Hodges
office: +442032898513
home: +376841522
mobile: +376380212


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

Re: boost::asio::read() gets stuck when there's no internet

Boost - Users mailing list
On 19/02/2021 17:19, Richard Hodges via Boost-users wrote:

> The TCP/IP protocol was designed to work over unreliable networks,
> including sections that hop over radio links and dial-up telephone lines.
>
> In a nutshell, the way the internet works is that packets are
> transmitted and it is assumed that they may or may not arrive at some
> time in the future. There are timeouts built in, but they are longer
> than you would probably want, on account of all the unreliable dial-ups
> between you and the other peer.
>
> Therefore, to involve a timeout you need to run a timer in parallel with
> the send/receive operation and cancel the operation if the timeout
> occurs before the operation has completed.

It probably would be easier to set SO_KEEPALIVE on the socket, then it
will close as soon as the physical connection disappears. This works for
any kind of socket, no timeouts needed.

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

Re: boost::asio::read() gets stuck when there's no internet

Boost - Users mailing list
Thanks Niall, I tried adding this to the code:

[code]
    boost::asio::socket_base::keep_alive ka_option(true);
    socket.lowest_layer().set_option(ka_option);
[/code]

and now it sometimes can come out of the read with an exception raised, which is good, but this happens only once in a while.

I haven't tried other ways yet such as what Richard Hodges suggested, as I need to delve deeper into that, and Boost or linux is new to me.

On Sat, Feb 20, 2021 at 12:58 AM Niall Douglas via Boost-users <[hidden email]> wrote:
On 19/02/2021 17:19, Richard Hodges via Boost-users wrote:
> The TCP/IP protocol was designed to work over unreliable networks,
> including sections that hop over radio links and dial-up telephone lines.
>
> In a nutshell, the way the internet works is that packets are
> transmitted and it is assumed that they may or may not arrive at some
> time in the future. There are timeouts built in, but they are longer
> than you would probably want, on account of all the unreliable dial-ups
> between you and the other peer.
>
> Therefore, to involve a timeout you need to run a timer in parallel with
> the send/receive operation and cancel the operation if the timeout
> occurs before the operation has completed.

It probably would be easier to set SO_KEEPALIVE on the socket, then it
will close as soon as the physical connection disappears. This works for
any kind of socket, no timeouts needed.

Niall
_______________________________________________
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: boost::asio::read() gets stuck when there's no internet

Boost - Users mailing list


On Sat, 20 Feb 2021 at 10:56, Child OfGod via Boost-users <[hidden email]> wrote:
Thanks Niall, I tried adding this to the code:

[code]
    boost::asio::socket_base::keep_alive ka_option(true);
    socket.lowest_layer().set_option(ka_option);
[/code]

and now it sometimes can come out of the read with an exception raised, which is good, but this happens only once in a while.

There are a number of options you can get to control the intervals and thresholds for TCP keepalives. Bear in mind that:
1) They will increase battery use on mobile devices and laptops because the radio will be transmitting more often.
2) They won't detect a server who's application has gone quiet while the TCP link stays up.

There is also SO_RCVTIMEO (on linux)


 
I haven't tried other ways yet such as what Richard Hodges suggested, as I need to delve deeper into that, and Boost or linux is new to me.

On Sat, Feb 20, 2021 at 12:58 AM Niall Douglas via Boost-users <[hidden email]> wrote:
On 19/02/2021 17:19, Richard Hodges via Boost-users wrote:
> The TCP/IP protocol was designed to work over unreliable networks,
> including sections that hop over radio links and dial-up telephone lines.
>
> In a nutshell, the way the internet works is that packets are
> transmitted and it is assumed that they may or may not arrive at some
> time in the future. There are timeouts built in, but they are longer
> than you would probably want, on account of all the unreliable dial-ups
> between you and the other peer.
>
> Therefore, to involve a timeout you need to run a timer in parallel with
> the send/receive operation and cancel the operation if the timeout
> occurs before the operation has completed.

It probably would be easier to set SO_KEEPALIVE on the socket, then it
will close as soon as the physical connection disappears. This works for
any kind of socket, no timeouts needed.

Niall
_______________________________________________
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


--
Richard Hodges
office: +442032898513
home: +376841522
mobile: +376380212


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