+ uint64_t hash = proto.get_hash();
+ auto i = find_member(protocols, hash, &ActiveProtocol::hash);
+ if(i==protocols.end())
+ {
+ const ActiveProtocol &last = protocols.back();
+ if(!last.protocol)
+ throw sequence_error("previous protocol is incomplete");
+ unsigned base = last.base;
+ base += (last.protocol->get_max_packet_id()+0xFF)&~0xFF;
+
+ if(base+max_id>std::numeric_limits<std::uint16_t>::max())
+ throw invalid_state("Communicator::add_protocol");
+
+ protocols.emplace_back(base, proto, recv);
+
+ if(socket.is_connected() && protocols.front().ready)
+ prepare_protocol(protocols.back());
+ }
+ else if(!i->protocol)
+ {
+ i->protocol = &proto;
+ i->last = i->base+max_id;
+ i->receiver = &recv;
+ accept_protocol(*i);
+ }
+}
+
+bool Communicator::is_protocol_ready(const Protocol &proto) const
+{
+ auto i = find_member(protocols, &proto, &ActiveProtocol::protocol);
+ return (i!=protocols.end() && i->ready);
+}
+
+void Communicator::send_data(size_t size)
+{
+ if(!good)
+ throw sequence_error("connection aborted");
+
+ try
+ {
+ socket.write(out_buf, size);
+ }
+ catch(const std::exception &e)
+ {
+ good = false;
+ if(signal_error.empty())
+ throw;
+ signal_error.emit(e);
+ }
+}
+
+void Communicator::connect_finished(const exception *exc)
+{
+ if(exc)
+ good = false;
+ else
+ prepare_protocol(protocols.front());