|
@@ -45,30 +45,39 @@ void NodeIO::return_frame(uint8_t *frame)
|
|
|
|
|
|
void NodeIO::send_header_data(uint64_t header, uint8_t *data, size_t len)
|
|
|
{
|
|
|
- std::vector<boost::asio::const_buffer> tosend;
|
|
|
+ commands_deque_lock.lock();
|
|
|
+ commands_inflight.push_back({header, data, len});
|
|
|
+ if (commands_inflight.size() == 1) {
|
|
|
+ async_send_commands();
|
|
|
+ }
|
|
|
+ commands_deque_lock.unlock();
|
|
|
+}
|
|
|
|
|
|
- // Put the header into the deque so it's in memory at a stable
|
|
|
- // address during the async write
|
|
|
- header_deque_lock.lock();
|
|
|
- headers_inflight.push_back(header);
|
|
|
+void NodeIO::async_send_commands()
|
|
|
+{
|
|
|
+ std::vector<boost::asio::const_buffer> tosend;
|
|
|
|
|
|
- uint64_t *headerp = &(headers_inflight.back());
|
|
|
- header_deque_lock.unlock();
|
|
|
- tosend.push_back(boost::asio::buffer(headerp, 5));
|
|
|
- if (data != NULL && len > 0) {
|
|
|
- tosend.push_back(boost::asio::buffer(data, len));
|
|
|
+ CommandTuple *commandp = &(commands_inflight.front());
|
|
|
+ tosend.push_back(boost::asio::buffer(&(std::get<0>(*commandp)), 5));
|
|
|
+ if (std::get<1>(*commandp) != NULL && std::get<2>(*commandp) > 0) {
|
|
|
+ tosend.push_back(boost::asio::buffer(std::get<1>(*commandp),
|
|
|
+ std::get<2>(*commandp)));
|
|
|
}
|
|
|
boost::asio::async_write(sock, tosend,
|
|
|
- [this, headerp, data](boost::system::error_code, std::size_t){
|
|
|
- // When the write completes, pop the header from the deque
|
|
|
+ [this, commandp](boost::system::error_code, std::size_t){
|
|
|
+ // When the write completes, pop the command from the deque
|
|
|
// (which should now be in the front)
|
|
|
- header_deque_lock.lock();
|
|
|
- assert(!headers_inflight.empty() &&
|
|
|
- &(headers_inflight.front()) == headerp);
|
|
|
- headers_inflight.pop_front();
|
|
|
- header_deque_lock.unlock();
|
|
|
+ commands_deque_lock.lock();
|
|
|
+ assert(!commands_inflight.empty() &&
|
|
|
+ &(commands_inflight.front()) == commandp);
|
|
|
+ uint8_t *data = std::get<1>(*commandp);
|
|
|
+ commands_inflight.pop_front();
|
|
|
+ if (commands_inflight.size() > 0) {
|
|
|
+ async_send_commands();
|
|
|
+ }
|
|
|
// And return the frame
|
|
|
return_frame(data);
|
|
|
+ commands_deque_lock.unlock();
|
|
|
});
|
|
|
}
|
|
|
|
|
@@ -98,35 +107,53 @@ void NodeIO::send_chunk(uint8_t *data, uint32_t chunk_len)
|
|
|
assert(chunksize_inflight <= msgsize_inflight);
|
|
|
}
|
|
|
|
|
|
-bool NodeIO::recv_header(uint64_t &header)
|
|
|
-{
|
|
|
- header = 0;
|
|
|
- try {
|
|
|
- boost::asio::read(sock, boost::asio::buffer(&header, 5));
|
|
|
- } catch (...) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-bool NodeIO::recv_chunk(uint64_t header, uint8_t *&data, size_t &len)
|
|
|
+void NodeIO::recv_commands(
|
|
|
+ std::function<void(boost::system::error_code)> error_cb,
|
|
|
+ std::function<void(uint32_t)> epoch_cb,
|
|
|
+ std::function<void(uint32_t)> message_cb,
|
|
|
+ std::function<void(uint8_t*,uint32_t)> chunk_cb)
|
|
|
{
|
|
|
- len = 0;
|
|
|
- data = NULL;
|
|
|
- assert((header & 0xff) == 0x02);
|
|
|
- size_t datalen = header >> 8;
|
|
|
- if (datalen > MAXCHUNKSIZE) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- try {
|
|
|
- boost::asio::read(sock,
|
|
|
- boost::asio::buffer(receive_frame, datalen));
|
|
|
- } catch (...) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- data = receive_frame;
|
|
|
- len = datalen;
|
|
|
- return true;
|
|
|
+ // Asynchronously read the header
|
|
|
+ receive_header = 0;
|
|
|
+ boost::asio::async_read(sock, boost::asio::buffer(&receive_header, 5),
|
|
|
+ [this, error_cb, epoch_cb, message_cb, chunk_cb]
|
|
|
+ (boost::system::error_code ec, std::size_t) {
|
|
|
+ if (ec) {
|
|
|
+ error_cb(ec);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if ((receive_header & 0xff) == 0x00) {
|
|
|
+ epoch_cb(uint32_t(receive_header >> 8));
|
|
|
+ recv_commands(error_cb, epoch_cb, message_cb, chunk_cb);
|
|
|
+ } else if ((receive_header & 0xff) == 0x01) {
|
|
|
+ assert(recv_msgsize_inflight == recv_chunksize_inflight);
|
|
|
+ recv_msgsize_inflight = uint32_t(receive_header >> 8);
|
|
|
+ recv_chunksize_inflight = 0;
|
|
|
+ message_cb(recv_msgsize_inflight);
|
|
|
+ recv_commands(error_cb, epoch_cb, message_cb, chunk_cb);
|
|
|
+ } else if ((receive_header & 0xff) == 0x02) {
|
|
|
+ uint32_t this_chunk_size = uint32_t(receive_header >> 8);
|
|
|
+ assert(recv_chunksize_inflight + this_chunk_size <=
|
|
|
+ recv_msgsize_inflight);
|
|
|
+ recv_chunksize_inflight += this_chunk_size;
|
|
|
+ boost::asio::async_read(sock, boost::asio::buffer(
|
|
|
+ receive_frame, this_chunk_size),
|
|
|
+ [this, error_cb, epoch_cb, message_cb, chunk_cb,
|
|
|
+ this_chunk_size]
|
|
|
+ (boost::system::error_code ecc, std::size_t) {
|
|
|
+ if (ecc) {
|
|
|
+ error_cb(ecc);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ chunk_cb(receive_frame, this_chunk_size);
|
|
|
+ recv_commands(error_cb, epoch_cb,
|
|
|
+ message_cb, chunk_cb);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ error_cb(boost::system::errc::make_error_code(
|
|
|
+ boost::system::errc::errc_t::invalid_argument));
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
NetIO::NetIO(boost::asio::io_context &io_context, const Config &config)
|