Boost.ASIO "deasynchronisation"

Hello, I'm developing networking library that provides RTMP-like networking using Boost.ASIO library. My problem is that any synchronous-access function breaks into many little functions that do some part of job and invoke async operation with "next" function as a handler, it makes the code really ugly and obfuscating. E.g. void hadshake that reads N bytes from peer, responds with those bytes + same count of other bytes, reads N bytes back and checks that they are the same. It breaks into: void start_handshake_wait(); void handle_handshake_wait(const boost::system::error_code&, std::size_t, buffer_ptr &); void handle_handshake_wait_write_dup(..same as above..); void handle_handshake_wait_write_mine(...); void handle_handshake_wait_read_mine_check(...); Every function uses boost::bind, so for some quite simple operation a lot of code is produced. Receiving a chunk of data breaks into: void read_header_head(); // header size depends on first byte void parse_header_head(); void parse_header_body(); void parse_chunk_body(); The only idea I came to is to use some tricks like coroutines. (Sorry for big listings) template<class T> class Context : public boost::enable_shared_from_this< Context<T> > { public: typedef boost::shared_ptr<Context<T> > ptr; private: typedef boost::shared_ptr<T> objptr_t; typedef void (T::*funcptr_t) (const BSYSECode&, std::size_t, Context<T>::ptr, buffer_ptr); objptr_t objptr_; funcptr_t funcptr_; public: std::map< std::string, buffer_ptr > buffers; int state; Context(objptr_t op, funcptr_t fp) : objptr_(op), funcptr_(fp), buffers(), state(0) { } template<typename AsyncReadStream> void async_read(AsyncReadStream &s, buffer_ptr buf) { boost::asio::async_read(s, *buf, boost::bind(funcptr_, objptr_, BASIOPErr, BASIOPBytes, this->shared_from_this(), buf)); } template<typename AsyncWriteStream> void async_write(AsyncWriteStream &s, buffer_ptr buf) { boost::asio::async_write(s, *buf, boost::bind(funcptr_, objptr_, BASIOPErr, BASIOPBytes, this->shared_from_this(), buf)); } }; #define CTX_PROLOG(c) \ if(!c) \ return; \ \ if(c->state == 0) { \ #define CTX_READ(c, s, b) \ c->state=__LINE__; \ c->async_read(s, b); \ return; \ } else if(c->state == __LINE__) { \ #define CTX_WRITE(c, s, b) \ c->state=__LINE__; \ c->async_write(s, b); \ return; \ } else if(c->state == __LINE__) { \ #define CTX_EPILOG \ } buffer_ptr is actually a shared_ptr to buffer, it's used to get buffer back to pool as it goes out of scope. With all this handshake becomes something more readable (to me, but it still cryptic; again, sorry for posting that much): class Handshaker : public boost::enable_shared_from_this<Handshaker> { private: Connection::ptr conn_; public: typedef boost::shared_ptr<Handshaker> ptr; typedef Context<Handshaker> context; Handshaker(Connection::ptr conn) : conn_(conn) { } void shake() { context::ptr ctx(new context(shared_from_this(), &Handshaker::perform)); perform(BSYSECode(), 0, ctx, buffer_ptr()); } private: void perform(const BSYSECode& err, std::size_t sz, context::ptr ctx, buffer_ptr buf) { if(err) return; CTX_PROLOG(ctx); CTX_READ(ctx, conn_->socket(), conn_->pool()->allocate(HandshakeSize)); CTX_WRITE(ctx, conn_->socket(), buf); ctx->buffers["mybuf"] = conn_->pool()->allocate(HandshakeSize); CTX_WRITE(ctx, conn_->socket(), ctx->buffers["mybuf"]); CTX_READ(ctx, conn_->socket(), conn_->pool()->allocate(HandshakeSize)); buffer_ptr mybuf = ctx->buffers["mybuf"]; buffer_ptr hisbuf = buf; if(boost::asio::buffer_size(*mybuf) != boost::asio::buffer_size(*hisbuf)) return; if(memcmp( boost::asio::buffer_cast<void*>(*mybuf), boost::asio::buffer_cast<void*>(*hisbuf), boost::asio::buffer_size(*mybuf) )) return; CTX_EPILOG; } }; Finally, the question: is there any library that provides functionality like that? I'd like to stick with it cause it looks like my implementation is really bad, HUGE bunch of limitations on code written that way, cryptic look, usage of macro, any local variable has to resort in ctx to survive async call.

Igore Dmit. wrote:
My problem is that any synchronous-access function breaks into many little functions that do some part of job and invoke async operation with "next" function as a handler, it makes the code really ugly and obfuscating.
I know exactly what you mean. We've started using the proposed Boost.Coroutine library (not yet official, a Google Summer of Code effort plus some bug fixes). You might be interested that the original author specifically targets use with ASIO. http://www.crystalclearsoftware.com/soc/coroutine/index.html http://www.crystalclearsoftware.com/soc/coroutine/coroutine/asio.html http://www.boostpro.com/vault/index.php?action=downloadfile&filename=boost-c... A couple of the bundled tests are built around ASIO.

"Igore" == Igore Dmit <trueorca@gmail.com> writes:
Igore> My problem is that any synchronous-access function breaks into Igore> many little functions that do some part of job and invoke async Igore> operation with "next" function as a handler, it makes the code Igore> really ugly and obfuscating.
"Nat" == Nat Goodspeed <nat@lindenlab.com> writes:
Nat> I know exactly what you mean. We've started using the proposed Nat> Boost.Coroutine library (not yet official, a Google Summer of Nat> Code effort plus some bug fixes). You might be interested that Nat> the original author specifically targets use with ASIO. The main author of ASIO itself is also a big proponent of using coroutines, and he demonstrates some tricks for using them cleanly on top of ASIO: http://blog.think-async.com/2009/07/wife-says-i-cant-believe-it-works.html http://blog.think-async.com/2009/08/secret-sauce-revealed.html http://blog.think-async.com/2009/08/composed-operations-coroutines-and-code.... One more option to investigate... Happy Hacking, t.

Anthony Foiani wrote:
The main author of ASIO itself is also a big proponent of using coroutines, and he demonstrates some tricks for using them cleanly on top of ASIO:
http://blog.think-async.com/2009/07/wife-says-i-cant-believe-it- works.html http://blog.think-async.com/2009/08/secret-sauce-revealed.html http://blog.think-async.com/2009/08/composed-operations-coroutines-and- code.html
Also see the new http example #4 in Boost 1.42, Cheers, Rutger
participants (4)
-
Anthony Foiani
-
Igore Dmit.
-
Nat Goodspeed
-
Rutger ter Borg