Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

TCP Socket.cancel doesn't cause scheduled writes to cancel

Aperta
#446 3 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
45/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Tranquilla
Stack tecnologico
cpp
Ambito
networking

Direzione di ricerca

Inizia compilando ed eseguendo il test unitario C++ fornito, quindi leggi la documentazione di basic_stream_socket::cancel e async_write e i punti di ingresso rilevanti dell’implementazione. Determina se il comportamento delle scritture accodate corrisponde al contratto di cancellazione documentato; il lavoro è completato quando l’errore atteso del callback e il comportamento del lavoro di io_context sono confermati o corretti con una modifica mirata al progetto.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Hi,

I'm trying to cancel any pending writes to a socket once realising the socket on the other end has gone away after not responding to messages. I was hoping to use basic_stream_socket::cancel but after calling it i can still poll the io context and get it to trigger writes i had queued up. I've produced the following unit test demonstrating what i mean.


#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE "C++ Unit Tests for Application"
#include <boost/test/unit_test.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/system/detail/errc.hpp>
#include <boost/system/detail/error_code.hpp>
#define BOOST_TEST_DYN_LINK
#include <boost/test/data/test_case.hpp>
#include <boost/test/framework.hpp>
#include <boost/asio.hpp>

using namespace boost::unit_test::framework;

BOOST_AUTO_TEST_SUITE(BoostSocketTest)

BOOST_AUTO_TEST_CASE(OnClearCallsCancelsIOContext) {
  // Arrange

  // Create a socket and listen on a port
  boost::asio::io_context child_io_context;
  boost::asio::ip::tcp::socket child_socket(child_io_context);
  boost::asio::ip::tcp::endpoint child_endpoint(boost::asio::ip::tcp::v4(), 5001);
  boost::asio::ip::tcp::acceptor child_acceptor(child_io_context);
  child_acceptor.open(child_endpoint.protocol());
  child_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
  child_acceptor.bind(child_endpoint);
  child_acceptor.listen();
  
  bool accepted = false;
  child_acceptor.async_accept(
    child_socket,
    [&accepted](boost::system::error_code ec)
    {
      if (ec) {
        BOOST_FAIL("failed to listen on child socket");
      } else {
        accepted = true;
      }
      return;
    });


  // Create another socket and connect it to the other one
  boost::asio::io_context parent_io_context;
  boost::asio::ip::tcp::socket parent_socket(parent_io_context);
  boost::asio::ip::tcp::resolver parent_resolver(parent_io_context);
  bool connected = false;
  parent_resolver.async_resolve(
    "localhost", "5001",
    [&connected, &parent_socket](const boost::system::error_code ec, boost::asio::ip::tcp::resolver::results_type results)
    {
        BOOST_TEST(ec == boost::system::errc::success, "failed to resolve");
        boost::asio::async_connect(parent_socket, results,
            [&connected](const boost::system::error_code& ec, const boost::asio::ip::tcp::endpoint& )
            {
                BOOST_TEST(ec == boost::system::errc::success, "failed to connect");
                connected = true;
            });
    });
  
  // Wait for the parent socket to connect to the 
  // child socket once completed the IO Contexts 
  // will have no work left to do so will set their
  // state to stopped
  while (!accepted or !connected) {
    child_io_context.poll();
    parent_io_context.poll();
  }

  BOOST_TEST((accepted && connected), "failed to connect or accept as such cannot simulate interrupted write");

  // Queue a message to be sent from the parent socket to the child socket
  std::string test_data = "test";
  bool callback_was_called = false;
  boost::asio::async_write(parent_socket, boost::asio::buffer((uint8_t*)(test_data.data()), test_data.size()),
      [&callback_was_called](boost::system::error_code ec, size_t) {
        callback_was_called = true;
        // Check the reccieved error code is a connection aborted one
        BOOST_TEST(ec == boost::system::errc::connection_aborted, "callback was not called with boost operation aborted");
        return;
      });

  // Restart the IO context as there is more work to do
  // and fail the test case if it fails to restart
  parent_io_context.restart();
  if(parent_io_context.stopped()){
    BOOST_FAIL("failed to restart parent io context");
  }

  // Act - cancel the message that was queued to be sent
  // this should call the callback and mean there is no
  // work to do at the next poll
  parent_socket.cancel();

  // Assert - that if you poll the io context it doesn't 
  // send and that the callback was called, if it was
  // it will already have checked it reccieved a connection
  // aborted error
  auto executed = parent_io_context.poll();
  BOOST_TEST(executed == 0, "Expected the executor to have done no work");
  BOOST_TEST(callback_was_called == true);
}

BOOST_AUTO_TEST_SUITE_END()

Compiled with
g++ -o BoostSocket_test -ansi -W -Wall -Wextra -Wno-non-virtual-dtor -std=c++23 -pthread -DNDEBUG -fPIC -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -ggdb -DBOOST_BIND_GLOBAL_PLACEHOLDERS -lboost_unit_test_framewor k BoostSocket_test.cpp
Fails the test as such

[root@9f0cfab1ff7b asio]# g++ -o BoostSocket_test -ansi -W -Wall -Wextra -Wno-non-virtual-dtor -std=c++23 -pthread -DNDEBUG -fPIC -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -ggdb -DBOOST_BIND_GLOBAL_PLACEHOLDERS -lboost_unit_test_framework BoostSocket_test.cpp
[root@9f0cfab1ff7b asio]# chmod +x BoostSocket_test
[root@9f0cfab1ff7b asio]# ./BoostSocket_test 
Running 1 test case...
BoostSocket_test.cpp(83): error: in "BoostSocketTest/OnClearCallsCancelsIOContext": callback was not called with boost operation aborted
BoostSocket_test.cpp(104): error: in "BoostSocketTest/OnClearCallsCancelsIOContext": Expected the executor to have done no work

*** 2 failures are detected in the test module "C++ Unit Tests for Application"

I've probably just misunderstood what kind of operations get cancelled by a cancel function call, any advice or pointers would be appreciated.

Thanks in advance
George

Lingua principale
C++
Stelle
1.6k
Fork
485
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

  • Nessun Dockerfile né file Docker Compose
  • Ha un modello di pull request
  • Nessuna guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di boostorg/asio

Tutte le issue di boostorg/asio

Issue simili

Altre issue su C++

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.