0

By making a read operation complete, I take to mean making socket::read_some return or having the handler passed to socket::async_read_some be invoked. Note that I'm on the receiver-side of the socket and it is me who have initiated the read operation. What I want to accomplish is to actively close a socket connection. The connection may also be passively closed, which is indicated by the read operation complete with boost::asio::error::eof.

I've tried socket::shutdown() followed by a call to socket::close() like the following:

boost::system::error_code err;
if (psocket->is_open()) {
    psocket->shutdown(tcp::socket::shutdown_both, err);
    psocket->close(err);
}

The problem with this approach is that if the connection is passively closed after the call to is_open() returned true, then on some OS like the Mac OS X, the following call to close() will result in a segmentation fault by accessing an already nulled pointer. On the other hand, a single call to shutdown() simply won't make the read operation complete. So, how can I actively make the read operation complete in a safe manner?

Lingxi
  • 14,579
  • 2
  • 37
  • 93
  • It's unclear what parts you're talking about. Do you shutdown from the sending end? Why don't show what happens on which side (a diagram could help) – sehe Sep 07 '15 at 08:32
  • I use the same approach than you, and I never experienced your problem in a Linux environment. Maybe it's worth to open a ticket to the asio maintainer to ask clarifications? – dau_sama Sep 07 '15 at 09:10
  • @sehe Sorry for the unclear description. Updated now. – Lingxi Sep 07 '15 at 13:13

1 Answers1

2

You cannot force async operation to complete status. But you can cancel all operations on socket by calling psocket->cancel(). This will call all your handlers with boost::asio::error::operation_aborted error code.

Galimov Albert
  • 7,269
  • 1
  • 24
  • 50
  • I'm not convinced the OP is talking about receiver-side cancellation. And canceling async operations sender-side is not going to signal "operation_aborted" on the receiving end, I don't think – sehe Sep 07 '15 at 09:57
  • @sehe probably i misunderstood his question, but it seems he want to cancel his own pending callbacks – Galimov Albert Sep 07 '15 at 10:11
  • @PSIAlt `cancel()` seems to be what I need. `shutdown()` prevents future operations on the socket, and `cancel()` then deals with the past. And although the documentation says that `cancel()` only works on asynchronous operations, according to my test run, it also works on synchronous read at least on my Windows 7. However, it does have portability issues as the documentation says. So, is there a better alternative? – Lingxi Sep 07 '15 at 13:20
  • @Lingxi seems currently its no alternative, docs say that `cancel` can be buggy on Win2003 and older. I use asio on linux and macos and not familiar with windows, but it looks like there is no other 100% way than closing the socket. – Galimov Albert Sep 07 '15 at 13:35
  • @PSIAlt So, `cancel()` seems to be my best option at present. `close()` just crashes my program on my friend's Mac pro, although it works fine on my Windows ~>_<~ To make things worse, my friend is the boss on this project :P – Lingxi Sep 07 '15 at 13:41
  • 1
    @Lingxi Your test run sounds as though it is violating thread safety and invoking undefined behavior. If `close()` is crashing the program, I would be very suspicious of undefined behavior being invoked as well. – Tanner Sansbury Sep 07 '15 at 16:35
  • @TannerSansbury Indeed, `tcp::socket` turns out to be non-thread-safe. I think Boost.Asio should provide a thread-safe version of it in the future. As to now, I can only wrap my own on top of `tcp::socket` myself. – Lingxi Sep 08 '15 at 05:24
  • @Lingxi asio docs say that only io_service and asio::strand are thread-safe. You can use asio::strand to protect your callbacks from working simultaneously in different threads, but i'd prefer to avoid threads when possible. – Galimov Albert Sep 08 '15 at 08:10
  • @Lingxi Before writing your own wrapper, consider using [strands](http://www.boost.org/doc/libs/1_59_0/doc/html/boost_asio/overview/core/strands.html), the library's supported way to prevent concurrent handler invocation. See this [answer](http://stackoverflow.com/a/12801042/1053968) for more details. – Tanner Sansbury Sep 08 '15 at 14:47