From aedb2c89aa3838485ff5ca85d12c6253d8a768a8 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 27 Jan 2024 13:30:36 +0100 Subject: [PATCH 01/17] SHV API 3 implementation part I --- libshvbroker/include/shv/broker/brokerapp.h | 5 +- libshvbroker/src/brokerapp.cpp | 115 ++-- libshvbroker/src/clientshvnode.cpp | 4 +- libshvbroker/src/clientshvnode.h | 2 +- .../src/rpc/clientconnectiononbroker.cpp | 19 +- .../src/rpc/clientconnectiononbroker.h | 4 +- libshvbroker/src/rpc/commonrpcclienthandle.h | 2 +- .../src/rpc/masterbrokerconnection.cpp | 22 +- libshvbroker/src/rpc/masterbrokerconnection.h | 4 +- .../include/shv/chainpack/chainpack.h | 2 +- libshvchainpack/include/shv/chainpack/rpc.h | 4 +- .../include/shv/chainpack/rpcdriver.h | 64 +-- .../include/shv/chainpack/rpcmessage.h | 42 +- .../include/shv/chainpack/rpcvalue.h | 1 + .../include/shv/chainpack/socketrpcdriver.h | 6 +- libshvchainpack/src/chainpack/rpc.cpp | 2 - libshvchainpack/src/chainpack/rpcdriver.cpp | 539 ++---------------- libshvchainpack/src/chainpack/rpcmessage.cpp | 65 ++- libshvchainpack/src/chainpack/rpcvalue.cpp | 20 +- .../src/chainpack/socketrpcdriver.cpp | 68 ++- libshviotqt/include/shv/iotqt/node/shvnode.h | 2 +- .../shv/iotqt/rpc/clientappclioptions.h | 2 - .../include/shv/iotqt/rpc/clientconnection.h | 2 +- .../include/shv/iotqt/rpc/serverconnection.h | 3 +- .../shv/iotqt/rpc/socketrpcconnection.h | 8 +- libshviotqt/src/node/shvnode.cpp | 20 +- libshviotqt/src/rpc/clientappclioptions.cpp | 1 - libshviotqt/src/rpc/clientconnection.cpp | 15 +- libshviotqt/src/rpc/serverconnection.cpp | 13 +- libshviotqt/src/rpc/socketrpcconnection.cpp | 35 +- .../serialportsocket/mockrpcconnection.cpp | 3 +- 31 files changed, 318 insertions(+), 776 deletions(-) diff --git a/libshvbroker/include/shv/broker/brokerapp.h b/libshvbroker/include/shv/broker/brokerapp.h index cd6ba86a9..24e6a9ca8 100644 --- a/libshvbroker/include/shv/broker/brokerapp.h +++ b/libshvbroker/include/shv/broker/brokerapp.h @@ -1,5 +1,6 @@ #pragma once +#include "shv/chainpack/rpcdriver.h" #ifdef USE_SHV_PATHS_GRANTS_CACHE #include @@ -68,7 +69,7 @@ class SHVBROKER_DECL_EXPORT BrokerApp : public QCoreApplication void onClientLogin(int connection_id); void onConnectedToMasterBrokerChanged(int connection_id, bool is_connected); - void onRpcDataReceived(int connection_id, shv::chainpack::Rpc::ProtocolType protocol_type, shv::chainpack::RpcValue::MetaData &&meta, std::string &&data); + void onRpcFrameReceived(int connection_id, shv::chainpack::RpcFrame &&frame); rpc::MasterBrokerConnection* masterBrokerConnectionForClient(int client_id); @@ -134,7 +135,7 @@ class SHVBROKER_DECL_EXPORT BrokerApp : public QCoreApplication void onClientConnected(int client_id); void sendNotifyToSubscribers(const std::string &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms); - bool sendNotifyToSubscribers(const shv::chainpack::RpcValue::MetaData &meta_data, const std::string &data); + bool sendNotifyToSubscribers(const shv::chainpack::RpcFrame &frame); static std::string brokerClientDirPath(int client_id); static std::string brokerClientAppPath(int client_id); diff --git a/libshvbroker/src/brokerapp.cpp b/libshvbroker/src/brokerapp.cpp index d1538f2a2..7fe58257d 100644 --- a/libshvbroker/src/brokerapp.cpp +++ b/libshvbroker/src/brokerapp.cpp @@ -1095,23 +1095,22 @@ void BrokerApp::onConnectedToMasterBrokerChanged(int connection_id, bool is_conn } } -void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::ProtocolType protocol_type, cp::RpcValue::MetaData &&meta, std::string &&data) +void BrokerApp::onRpcFrameReceived(int connection_id, shv::chainpack::RpcFrame &&frame) { - cp::RpcMessage::setProtocolType(meta, protocol_type); - if(cp::RpcMessage::isRegisterRevCallerIds(meta)) - cp::RpcMessage::pushRevCallerId(meta, connection_id); - if(cp::RpcMessage::isRequest(meta)) { - shvMessage() << "RPC request on broker connection id:" << connection_id << "protocol type:" << shv::chainpack::Rpc::protocolTypeToString(protocol_type) << meta.toPrettyString(); + if(cp::RpcMessage::isRegisterRevCallerIds(frame.meta)) + cp::RpcMessage::pushRevCallerId(frame.meta, connection_id); + if(cp::RpcMessage::isRequest(frame.meta)) { + shvMessage() << "RPC request on broker connection id:" << connection_id << frame.meta.toPrettyString(); // prepare response for catch block // it cannot be constructed from meta, since meta is moved in the try block - shv::chainpack::RpcResponse rsp = cp::RpcResponse::forRequest(meta); + shv::chainpack::RpcResponse rsp = cp::RpcResponse::forRequest(frame.meta); rpc::ClientConnectionOnBroker *client_connection = clientConnectionById(connection_id); rpc::MasterBrokerConnection *master_broker_connection = masterBrokerConnectionById(connection_id); rpc::CommonRpcClientHandle *connection_handle = client_connection; if(connection_handle == nullptr) connection_handle = master_broker_connection; try { - std::string shv_path = cp::RpcMessage::shvPath(meta).toString(); + std::string shv_path = cp::RpcMessage::shvPath(frame.meta).toString(); bool is_service_provider_mount_point_relative_call = false; if(connection_handle) { using ShvUrl = shv::core::utils::ShvUrl; @@ -1127,20 +1126,20 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc if(!client_connection->isSlaveBrokerConnection()) { { // erase grant from client connections - cp::RpcValue ag = cp::RpcMessage::accessGrant(meta); + cp::RpcValue ag = cp::RpcMessage::accessGrant(frame.meta); if(ag.isValid() /*&& !ag.isUserLogin()*/) { shvWarning() << "Client request with access grant specified not allowed, erasing:" << ag.toPrettyString(); - cp::RpcMessage::setAccessGrant(meta, cp::RpcValue()); + cp::RpcMessage::setAccessGrant(frame.meta, cp::RpcValue()); } } { // fill in user_id, for current client issuing rpc request - cp::RpcValue user_id = cp::RpcRequest::userId(meta); + cp::RpcValue user_id = cp::RpcRequest::userId(frame.meta); cp::RpcValue::Map m = user_id.asMap(); m[cp::Rpc::KEY_SHV_USER] = client_connection->userName(); m[cp::Rpc::KEY_BROKER_ID] = cliOptions()->brokerId(); user_id = m; - cp::RpcRequest::setUserId(meta, user_id); + cp::RpcRequest::setUserId(frame.meta, user_id); } } if(shv_url.isUpTree()) { @@ -1149,18 +1148,18 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc logServiceProvidersM() << "Up-tree SP call, resolved local path:" << resolved_local_path << "service node:" << service_node; if(service_node) { logServiceProvidersM() << shv_path << "service path resolved on this broker, making path absolute:" << resolved_local_path; - cp::RpcRequest::setShvPath(meta, resolved_local_path); + cp::RpcRequest::setShvPath(frame.meta, resolved_local_path); is_service_provider_mount_point_relative_call = shv_url.isUpTreeMountPointRelative(); } else { rpc::MasterBrokerConnection *master_broker = masterBrokerConnectionForClient(connection_id); logServiceProvidersM() << "service path not found, forwarding it to master broker:" << master_broker; if(master_broker == nullptr) - ACCESS_EXCEPTION("Cannot call service provider path " + cp::RpcMessage::shvPath(meta).toString() + ", there is no master broker to forward the request."); + ACCESS_EXCEPTION("Cannot call service provider path " + cp::RpcMessage::shvPath(frame.meta).toString() + ", there is no master broker to forward the request."); logServiceProvidersM() << "forwarded shv path:" << resolved_local_path; - cp::RpcRequest::setShvPath(meta, resolved_local_path); - cp::RpcMessage::pushCallerId(meta, connection_id); - master_broker->sendRawData(meta, std::move(data)); + cp::RpcRequest::setShvPath(frame.meta, resolved_local_path); + cp::RpcMessage::pushCallerId(frame.meta, connection_id); + master_broker->sendFrame(std::move(frame)); return; } } @@ -1176,23 +1175,23 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc return true; }; if (shv::core::utils::ShvPath::startsWithPath(shv_path, shv::iotqt::node::ShvNode::LOCAL_NODE_HACK)) { - if(has_dot_local_access(meta)) { + if(has_dot_local_access(frame.meta)) { shv::core::StringView path(shv_path); shv::core::utils::ShvPath::takeFirsDir(path); - cp::RpcMessage::setShvPath(meta, std::string{path}); + cp::RpcMessage::setShvPath(frame.meta, std::string{path}); } else { ACCESS_EXCEPTION("Insufficient access rights to make call on node: " + shv::iotqt::node::ShvNode::LOCAL_NODE_HACK); } } else if(shv_url.isPlain()) { - if (shv_path.empty() && cp::RpcMessage::method(meta) == cp::Rpc::METH_LS && has_dot_local_access(meta)) { + if (shv_path.empty() && cp::RpcMessage::method(frame.meta) == cp::Rpc::METH_LS && has_dot_local_access(frame.meta)) { /// if superuser calls 'ls' on broker exported root, then '.local' dir is added to the ls result /// this enables access slave broker root via virtual '.local' directory - meta.setValue(shv::iotqt::node::ShvNode::ADD_LOCAL_TO_LS_RESULT_HACK_META_KEY, true); + frame.meta.setValue(shv::iotqt::node::ShvNode::ADD_LOCAL_TO_LS_RESULT_HACK_META_KEY, true); } auto path = master_broker_connection->masterExportedToLocalPath(shv_path); - cp::RpcMessage::setShvPath(meta, path); + cp::RpcMessage::setShvPath(frame.meta, path); } else if(shv_url.isDownTree()) { iotqt::node::ShvNode *service_node = nodeForService(shv_url); @@ -1200,28 +1199,28 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc if(service_node) { string resolved_local_path = shv::core::utils::joinPath(std::string{shv_url.service()}, std::string{shv_url.pathPart()}); logServiceProvidersM() << shv_path << "service path resolved on this broker, making path absolute:" << resolved_local_path; - cp::RpcRequest::setShvPath(meta, resolved_local_path); + cp::RpcRequest::setShvPath(frame.meta, resolved_local_path); } else { string exported_path = master_broker_connection->exportedShvPath(); string resolved_path = shv::core::utils::joinPath(exported_path, std::string{shv_url.pathPart()}); resolved_path = shv::core::utils::ShvUrl::makeShvUrlString(shv_url.type(), shv_url.service(), shv_url.fullBrokerId(), resolved_path); logServiceProvidersM() << shv_path << "service path not resolved on this broker, preppending exported path:" << resolved_path; - cp::RpcRequest::setShvPath(meta, resolved_path); + cp::RpcRequest::setShvPath(frame.meta, resolved_path); } } } - const std::string method = cp::RpcMessage::method(meta).asString(); - const std::string resolved_shv_path = cp::RpcMessage::shvPath(meta).asString(); + const std::string method = cp::RpcMessage::method(frame.meta).asString(); + const std::string resolved_shv_path = cp::RpcMessage::shvPath(frame.meta).asString(); ShvUrl resolved_shv_url(resolved_shv_path); cp::AccessGrant acg; - acg = aclManager()->accessGrantForShvPath(connection_handle->loggedUserName(), resolved_shv_url, method, connection_handle->isMasterBrokerConnection(), is_service_provider_mount_point_relative_call, cp::RpcMessage::accessGrant(meta)); + acg = aclManager()->accessGrantForShvPath(connection_handle->loggedUserName(), resolved_shv_url, method, connection_handle->isMasterBrokerConnection(), is_service_provider_mount_point_relative_call, cp::RpcMessage::accessGrant(frame.meta)); if(acg.isValid()) { auto level = iotqt::node::ShvNode::basicGrantToAccessLevel(acg); if(level != shv::chainpack::MetaMethod::AccessLevel::None) { if(level < shv::chainpack::MetaMethod::AccessLevel::Write) { // remove iser id for read operations - cp::RpcMessage::setUserId(meta, {}); + cp::RpcMessage::setUserId(frame.meta, {}); } } } @@ -1230,10 +1229,10 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc shvWarning() << "Acces to shv path '" + resolved_shv_path + "' not granted for master broker"; ACCESS_EXCEPTION("Acces to shv path '" + resolved_shv_path + "' not granted for user '" + connection_handle->loggedUserName() + "'"); } - cp::RpcMessage::setAccessGrant(meta, acg.toRpcValue()); - cp::RpcMessage::pushCallerId(meta, connection_id); + cp::RpcMessage::setAccessGrant(frame.meta, acg.toRpcValue()); + cp::RpcMessage::pushCallerId(frame.meta, connection_id); if(m_nodesTree->root()) { - m_nodesTree->root()->handleRawRpcRequest(std::move(meta), std::move(data)); + m_nodesTree->root()->handleRpcFrame(std::move(frame)); } else { SHV_EXCEPTION("Device tree root node is NULL"); @@ -1252,17 +1251,17 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc } } } - else if(cp::RpcMessage::isResponse(meta)) { - shvDebug() << "RESPONSE conn id:" << connection_id << meta.toPrettyString(); - shv::chainpack::RpcValue orig_caller_ids = cp::RpcMessage::callerIds(meta); - cp::RpcValue::Int caller_id = cp::RpcMessage::popCallerId(meta); + else if(cp::RpcMessage::isResponse(frame.meta)) { + shvDebug() << "RESPONSE conn id:" << connection_id << frame.meta.toPrettyString(); + shv::chainpack::RpcValue orig_caller_ids = cp::RpcMessage::callerIds(frame.meta); + cp::RpcValue::Int caller_id = cp::RpcMessage::popCallerId(frame.meta); shvDebug() << "top caller id:" << caller_id; if(caller_id > 0) { - cp::TunnelCtl tctl = cp::RpcMessage::tunnelCtl(meta); + cp::TunnelCtl tctl = cp::RpcMessage::tunnelCtl(frame.meta); if(tctl.state() == cp::TunnelCtl::State::FindTunnelRequest) { - logTunnelD() << "FindTunnelRequest received:" << meta.toPrettyString(); + logTunnelD() << "FindTunnelRequest received:" << frame.meta.toPrettyString(); cp::FindTunnelReqCtl find_tunnel_request(tctl); - bool last_broker = cp::RpcValueGenList(cp::RpcMessage::callerIds(meta)).empty(); + bool last_broker = cp::RpcValueGenList(cp::RpcMessage::callerIds(frame.meta)).empty(); bool is_public_node; std::string server_ip = primaryIPAddress(is_public_node); if(is_public_node || (last_broker && find_tunnel_request.host().empty())) { @@ -1274,9 +1273,9 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc if(last_broker) { cp::FindTunnelRespCtl find_tunnel_response = cp::FindTunnelRespCtl::fromFindTunnelRequest(find_tunnel_request); cp::RpcMessage msg; - msg.setRequestId(cp::RpcMessage::requestId(meta)); + msg.setRequestId(cp::RpcMessage::requestId(frame.meta)); // send response to FindTunnelRequest, remove top client id, since it is this connection id - msg.setCallerIds(cp::RpcMessage::revCallerIds(meta)); + msg.setCallerIds(cp::RpcMessage::revCallerIds(frame.meta)); int top_connection_id = msg.popCallerId(); if(top_connection_id != connection_id) { shvError() << "(top_connection_id != connection_id) this should never happen"; @@ -1290,12 +1289,12 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc } return; } - cp::RpcMessage::setTunnelCtl(meta, find_tunnel_request); - logTunnelD() << "Forwarding FindTunnelRequest:" << meta.toPrettyString(); + cp::RpcMessage::setTunnelCtl(frame.meta, find_tunnel_request); + logTunnelD() << "Forwarding FindTunnelRequest:" << frame.meta.toPrettyString(); } rpc::CommonRpcClientHandle *cch = commonClientConnectionById(caller_id); if(cch) { - cch->sendRawData(meta, std::move(data)); + cch->sendFrame(std::move(frame)); } else { shvWarning() << "Got RPC response for not-exists connection, may be it was closed meanwhile. Connection id:" << caller_id; @@ -1303,13 +1302,13 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc } else { // broker messages like create master broker subscription - shvDebug() << "Got RPC response without src connection specified, it should be this broker call like create master broker subscription, throwing message away." << meta.toPrettyString(); + shvDebug() << "Got RPC response without src connection specified, it should be this broker call like create master broker subscription, throwing message away." << frame.meta.toPrettyString(); } } - else if(cp::RpcMessage::isSignal(meta)) { - logSigResolveD() << "SIGNAL:" << meta.toPrettyString() << "from:" << connection_id; + else if(cp::RpcMessage::isSignal(frame.meta)) { + logSigResolveD() << "SIGNAL:" << frame.meta.toPrettyString() << "from:" << connection_id; - const std::string sig_shv_path = cp::RpcMessage::shvPath(meta).asString(); + const std::string sig_shv_path = cp::RpcMessage::shvPath(frame.meta).asString(); std::string full_shv_path = sig_shv_path; std::string mount_point; rpc::ClientConnectionOnBroker *client_connection = clientConnectionById(connection_id); @@ -1322,16 +1321,16 @@ void BrokerApp::onRpcDataReceived(int connection_id, shv::chainpack::Rpc::Protoc shvError() << "SIGNAL with empty shv path received from master broker connection."; } else { - cp::RpcMessage::setShvPath(meta, full_shv_path); - bool sig_sent = sendNotifyToSubscribers(meta, data); + cp::RpcMessage::setShvPath(frame.meta, full_shv_path); + bool sig_sent = sendNotifyToSubscribers(frame); if(!sig_sent && client_connection && client_connection->isSlaveBrokerConnection()) { - logSubscriptionsD() << "Rejecting unsubscribed signal, shv_path:" << full_shv_path << "method:" << cp::RpcMessage::method(meta).asString(); + logSubscriptionsD() << "Rejecting unsubscribed signal, shv_path:" << full_shv_path << "method:" << cp::RpcMessage::method(frame.meta).asString(); cp::RpcRequest rq; rq.setRequestId(client_connection->nextRequestId()); rq.setMethod(cp::Rpc::METH_REJECT_NOT_SUBSCRIBED) .setParams(cp::RpcValue::Map{ { cp::Rpc::PAR_PATH, sig_shv_path}, - { cp::Rpc::PAR_METHOD, cp::RpcMessage::method(meta).toString()}}) + { cp::Rpc::PAR_METHOD, cp::RpcMessage::method(frame.meta).toString()}}) .setShvPath(cp::Rpc::DIR_BROKER_APP); client_connection->sendMessage(rq); } @@ -1393,25 +1392,25 @@ std::string BrokerApp::brokerClientAppPath(int client_id) return brokerClientDirPath(client_id) + "/app"; } -bool BrokerApp::sendNotifyToSubscribers(const shv::chainpack::RpcValue::MetaData &meta_data, const std::string &data) +bool BrokerApp::sendNotifyToSubscribers(const chainpack::RpcFrame &frame) { // send it to all clients for now bool subs_sent = false; for(rpc::CommonRpcClientHandle *conn : allClientConnections()) { if(conn->isConnectedAndLoggedIn()) { - const cp::RpcValue shv_path = cp::RpcMessage::shvPath(meta_data); - const cp::RpcValue method = cp::RpcMessage::method(meta_data); + const cp::RpcValue shv_path = cp::RpcMessage::shvPath(frame.meta); + const cp::RpcValue method = cp::RpcMessage::method(frame.meta); int subs_ix = conn->isSubscribed(shv_path.toString(), method.asString()); if(subs_ix >= 0) { const rpc::ClientConnectionOnBroker::Subscription &subs = conn->subscriptionAt(static_cast(subs_ix)); std::string new_path = conn->toSubscribedPath(subs, shv_path.asString()); if(new_path == shv_path.asString()) { - conn->sendRawData(meta_data, std::string(data)); + conn->sendFrame(chainpack::RpcFrame(frame)); } else { - shv::chainpack::RpcValue::MetaData md2(meta_data); - cp::RpcMessage::setShvPath(md2, new_path); - conn->sendRawData(md2, std::string(data)); + auto frame2 = frame; + cp::RpcMessage::setShvPath(frame2.meta, new_path); + conn->sendFrame(std::move(frame2)); } subs_sent = true; } diff --git a/libshvbroker/src/clientshvnode.cpp b/libshvbroker/src/clientshvnode.cpp index c9f0c4b42..e3bd9c52e 100644 --- a/libshvbroker/src/clientshvnode.cpp +++ b/libshvbroker/src/clientshvnode.cpp @@ -45,11 +45,11 @@ void ClientShvNode::removeConnection(rpc::ClientConnectionOnBroker *conn) deleteLater(); } -void ClientShvNode::handleRawRpcRequest(shv::chainpack::RpcValue::MetaData &&meta, std::string &&data) +void ClientShvNode::handleRpcFrame(chainpack::RpcFrame &&frame) { rpc::ClientConnectionOnBroker *conn = connection(); if(conn) - conn->sendRawData(meta, std::move(data)); + conn->sendFrame(std::move(frame)); } shv::chainpack::RpcValue ClientShvNode::hasChildren(const StringViewList &shv_path) diff --git a/libshvbroker/src/clientshvnode.h b/libshvbroker/src/clientshvnode.h index e80c1f672..15dd239e4 100644 --- a/libshvbroker/src/clientshvnode.h +++ b/libshvbroker/src/clientshvnode.h @@ -22,7 +22,7 @@ class ClientShvNode : public shv::iotqt::node::ShvNode void addConnection(rpc::ClientConnectionOnBroker *conn); void removeConnection(rpc::ClientConnectionOnBroker *conn); - void handleRawRpcRequest(shv::chainpack::RpcValue::MetaData &&meta, std::string &&data) override; + void handleRpcFrame(chainpack::RpcFrame &&frame) override; shv::chainpack::RpcValue hasChildren(const StringViewList &shv_path) override; private: QList m_connections; diff --git a/libshvbroker/src/rpc/clientconnectiononbroker.cpp b/libshvbroker/src/rpc/clientconnectiononbroker.cpp index 1e45ad191..25a71b265 100644 --- a/libshvbroker/src/rpc/clientconnectiononbroker.cpp +++ b/libshvbroker/src/rpc/clientconnectiononbroker.cpp @@ -167,18 +167,16 @@ void ClientConnectionOnBroker::sendMessage(const shv::chainpack::RpcMessage &rpc { logRpcMsg() << SND_LOG_ARROW << "client id:" << connectionId() - << "protocol_type:" << static_cast(protocolType()) << shv::chainpack::Rpc::protocolTypeToString(protocolType()) << rpc_msg.toPrettyString(); - Super::sendMessage(rpc_msg); + chainpack::RpcDriver::sendRpcMessage(rpc_msg); } -void ClientConnectionOnBroker::sendRawData(const shv::chainpack::RpcValue::MetaData &meta_data, std::string &&data) +void ClientConnectionOnBroker::sendFrame(chainpack::RpcFrame &&frame) { logRpcMsg() << SND_LOG_ARROW << "client id:" << connectionId() - << "protocol_type:" << static_cast(protocolType()) << shv::chainpack::Rpc::protocolTypeToString(protocolType()) - << RpcDriver::dataToPrettyCpon(shv::chainpack::RpcMessage::protocolType(meta_data), meta_data, data); - Super::sendRawData(meta_data, std::move(data)); + << RpcDriver::frameToPrettyCpon(frame); + chainpack::RpcDriver::sendRpcFrame(std::move(frame)); } ClientConnectionOnBroker::Subscription ClientConnectionOnBroker::createSubscription(const std::string &shv_path, const std::string &method) @@ -269,20 +267,19 @@ string ClientConnectionOnBroker::toSubscribedPath(const CommonRpcClientHandle::S return signal_path; } -void ClientConnectionOnBroker::onRpcDataReceived(shv::chainpack::Rpc::ProtocolType protocol_type, shv::chainpack::RpcValue::MetaData &&md, string &&msg_data) +void ClientConnectionOnBroker::onRpcFrameReceived(chainpack::RpcFrame &&frame) { logRpcMsg() << RCV_LOG_ARROW << "client id:" << connectionId() - << "protocol_type:" << static_cast(protocol_type) << shv::chainpack::Rpc::protocolTypeToString(protocol_type) - << RpcDriver::dataToPrettyCpon(protocol_type, md, msg_data, 0, msg_data.size()); + << RpcDriver::frameToPrettyCpon(frame); try { if(isLoginPhase()) { - Super::onRpcDataReceived(protocol_type, std::move(md), std::move(msg_data)); + Super::onRpcFrameReceived(std::move(frame)); return; } if(m_idleWatchDogTimer) m_idleWatchDogTimer->start(); - BrokerApp::instance()->onRpcDataReceived(connectionId(), protocol_type, std::move(md), std::move(msg_data)); + BrokerApp::instance()->onRpcFrameReceived(connectionId(), std::move(frame)); } catch (std::exception &e) { shvError() << e.what(); diff --git a/libshvbroker/src/rpc/clientconnectiononbroker.h b/libshvbroker/src/rpc/clientconnectiononbroker.h index aa2cf2d87..4698d2fd8 100644 --- a/libshvbroker/src/rpc/clientconnectiononbroker.h +++ b/libshvbroker/src/rpc/clientconnectiononbroker.h @@ -47,7 +47,7 @@ class ClientConnectionOnBroker : public shv::iotqt::rpc::ServerConnection, publi void setIdleWatchDogTimeOut(int sec); void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) override; - void sendRawData(const shv::chainpack::RpcValue::MetaData &meta_data, std::string &&data) override; + void sendFrame(shv::chainpack::RpcFrame &&frame) override; Subscription createSubscription(const std::string &shv_path, const std::string &method) override; std::string toSubscribedPath(const Subscription &subs, const std::string &signal_path) const override; @@ -56,7 +56,7 @@ class ClientConnectionOnBroker : public shv::iotqt::rpc::ServerConnection, publi void setLoginResult(const chainpack::UserLoginResult &result) override; private: void onSocketConnectedChanged(bool is_connected); - void onRpcDataReceived(shv::chainpack::Rpc::ProtocolType protocol_type, shv::chainpack::RpcValue::MetaData &&md, std::string &&msg_data) override; + void onRpcFrameReceived(chainpack::RpcFrame &&frame) override; bool checkTunnelSecret(const std::string &s); QVector callerIdsToList(const shv::chainpack::RpcValue &caller_ids); diff --git a/libshvbroker/src/rpc/commonrpcclienthandle.h b/libshvbroker/src/rpc/commonrpcclienthandle.h index e240ee5dd..39d5cf8eb 100644 --- a/libshvbroker/src/rpc/commonrpcclienthandle.h +++ b/libshvbroker/src/rpc/commonrpcclienthandle.h @@ -42,7 +42,7 @@ class CommonRpcClientHandle virtual bool isSlaveBrokerConnection() const = 0; virtual bool isMasterBrokerConnection() const = 0; - virtual void sendRawData(const shv::chainpack::RpcValue::MetaData &meta_data, std::string &&data) = 0; + virtual void sendFrame(chainpack::RpcFrame &&frame) = 0; virtual void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) = 0; protected: std::vector m_subscriptions; diff --git a/libshvbroker/src/rpc/masterbrokerconnection.cpp b/libshvbroker/src/rpc/masterbrokerconnection.cpp index 956006651..b3bfecf43 100644 --- a/libshvbroker/src/rpc/masterbrokerconnection.cpp +++ b/libshvbroker/src/rpc/masterbrokerconnection.cpp @@ -85,13 +85,12 @@ bool MasterBrokerConnection::isMasterBrokerConnection() const return true; } -void MasterBrokerConnection::sendRawData(const shv::chainpack::RpcValue::MetaData &meta_data, std::string &&data) +void MasterBrokerConnection::sendFrame(chainpack::RpcFrame &&frame) { logRpcMsg() << SND_LOG_ARROW << "client id:" << connectionId() - << "protocol_type:" << static_cast(protocolType()) << shv::chainpack::Rpc::protocolTypeToString(protocolType()) - << RpcDriver::dataToPrettyCpon(shv::chainpack::RpcMessage::protocolType(meta_data), meta_data, data, 0); - Super::sendRawData(meta_data, std::move(data)); + << RpcDriver::frameToPrettyCpon(frame); + Super::sendRpcFrame(std::move(frame)); } void MasterBrokerConnection::sendMessage(const shv::chainpack::RpcMessage &rpc_msg) @@ -145,27 +144,26 @@ const std::string& MasterBrokerConnection::exportedShvPath() const return m_exportedShvPath; } -void MasterBrokerConnection::onRpcDataReceived(shv::chainpack::Rpc::ProtocolType protocol_type, shv::chainpack::RpcValue::MetaData &&md, std::string &&msg_data) +void MasterBrokerConnection::onRpcFrameReceived(chainpack::RpcFrame &&frame) { logRpcMsg() << RpcDriver::RCV_LOG_ARROW << "client id:" << connectionId() - << "protocol_type:" << static_cast(protocol_type) << shv::chainpack::Rpc::protocolTypeToString(protocol_type) - << RpcDriver::dataToPrettyCpon(protocol_type, md, msg_data, 0, msg_data.size()); + << RpcDriver::frameToPrettyCpon(frame); try { if(isLoginPhase()) { - Super::onRpcDataReceived(protocol_type, std::move(md), std::move(msg_data)); + Super::onRpcFrameReceived(std::move(frame)); return; } - if(cp::RpcMessage::isRequest(md)) { + if(cp::RpcMessage::isRequest(frame.meta)) { } - else if(cp::RpcMessage::isResponse(md)) { - int rq_id = cp::RpcMessage::requestId(md).toInt(); + else if(cp::RpcMessage::isResponse(frame.meta)) { + int rq_id = cp::RpcMessage::requestId(frame.meta).toInt(); if(rq_id == m_connectionState.pingRqId) { m_connectionState.pingRqId = 0; return; } } - BrokerApp::instance()->onRpcDataReceived(connectionId(), protocol_type, std::move(md), std::move(msg_data)); + BrokerApp::instance()->onRpcFrameReceived(connectionId(), std::move(frame)); } catch (std::exception &e) { shvError() << e.what(); diff --git a/libshvbroker/src/rpc/masterbrokerconnection.h b/libshvbroker/src/rpc/masterbrokerconnection.h index 3b80c5c48..151eed5db 100644 --- a/libshvbroker/src/rpc/masterbrokerconnection.h +++ b/libshvbroker/src/rpc/masterbrokerconnection.h @@ -26,7 +26,7 @@ class MasterBrokerConnection : public shv::iotqt::rpc::DeviceConnection, public bool isSlaveBrokerConnection() const override; bool isMasterBrokerConnection() const override; - void sendRawData(const shv::chainpack::RpcValue::MetaData &meta_data, std::string &&data) override; + void sendFrame(shv::chainpack::RpcFrame &&frame) override; void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) override; Subscription createSubscription(const std::string &shv_path, const std::string &method) override; @@ -39,7 +39,7 @@ class MasterBrokerConnection : public shv::iotqt::rpc::DeviceConnection, public void setOptions(const shv::chainpack::RpcValue &slave_broker_options); shv::chainpack::RpcValue options(); protected: - void onRpcDataReceived(shv::chainpack::Rpc::ProtocolType protocol_type, shv::chainpack::RpcValue::MetaData &&md, std::string &&msg_data) override; + void onRpcFrameReceived(shv::chainpack::RpcFrame &&frame) override; protected: std::string m_exportedShvPath; shv::chainpack::RpcValue m_options; diff --git a/libshvchainpack/include/shv/chainpack/chainpack.h b/libshvchainpack/include/shv/chainpack/chainpack.h index d893d46f7..553ac75d2 100644 --- a/libshvchainpack/include/shv/chainpack/chainpack.h +++ b/libshvchainpack/include/shv/chainpack/chainpack.h @@ -1,7 +1,7 @@ #pragma once -#include "rpcvalue.h" #include +#include namespace shv { namespace chainpack { diff --git a/libshvchainpack/include/shv/chainpack/rpc.h b/libshvchainpack/include/shv/chainpack/rpc.h index db5e96bb2..9c94d15fb 100644 --- a/libshvchainpack/include/shv/chainpack/rpc.h +++ b/libshvchainpack/include/shv/chainpack/rpc.h @@ -2,15 +2,13 @@ #include -#include - namespace shv { namespace chainpack { class SHVCHAINPACK_DECL_EXPORT Rpc { public: - enum class ProtocolType {Invalid = 0, ChainPack, Cpon, JsonRpc}; + enum class ProtocolType {Invalid = 0, ChainPack}; static const char* protocolTypeToString(ProtocolType pv); static constexpr auto OPT_IDLE_WD_TIMEOUT = "idleWatchDogTimeOut"; diff --git a/libshvchainpack/include/shv/chainpack/rpcdriver.h b/libshvchainpack/include/shv/chainpack/rpcdriver.h index 8f5d4da06..ce0d79828 100644 --- a/libshvchainpack/include/shv/chainpack/rpcdriver.h +++ b/libshvchainpack/include/shv/chainpack/rpcdriver.h @@ -4,10 +4,7 @@ #include #include -#include #include -#include -#include namespace shv { namespace chainpack { @@ -23,73 +20,28 @@ class SHVCHAINPACK_DECL_EXPORT RpcDriver explicit RpcDriver(); virtual ~RpcDriver(); - Rpc::ProtocolType protocolType() const; - void setProtocolType(Rpc::ProtocolType v); - - void sendRpcValue(const RpcValue &msg); - void sendRawData(std::string &&data); - virtual void sendRawData(const RpcValue::MetaData &meta_data, std::string &&data); - - virtual void clearSendBuffers(); + void sendRpcMessage(const RpcMessage &msg); + virtual void sendRpcFrame(RpcFrame &&frame); static int defaultRpcTimeoutMsec(); static void setDefaultRpcTimeoutMsec(int msec); - static RpcMessage composeRpcMessage(RpcValue::MetaData &&meta_data, const std::string &data, std::string *errmsg = nullptr); - - static size_t decodeMetaData(RpcValue::MetaData &meta_data, Rpc::ProtocolType protocol_type, const std::string &data, size_t start_pos); - static RpcValue decodeData(Rpc::ProtocolType protocol_type, const std::string &data, size_t start_pos); - static std::string codeRpcValue(Rpc::ProtocolType protocol_type, const RpcValue &val); - - static std::string dataToPrettyCpon(shv::chainpack::Rpc::ProtocolType protocol_type, const shv::chainpack::RpcValue::MetaData &md, const std::string &data, size_t start_pos = 0, size_t data_len = 0); -protected: - struct SHVCHAINPACK_DECL_EXPORT MessageData - { - std::string metaData; - std::string data; - - MessageData(); - MessageData(std::string &&meta_data_, std::string &&data_); - MessageData(std::string &&data_); - MessageData(MessageData &&) noexcept; - - bool empty() const; - size_t size() const; - }; + static std::string frameToPrettyCpon(const RpcFrame &frame); protected: virtual bool isOpen() = 0; - /// called before RpcMessage data is about to written - virtual void writeMessageBegin() = 0; - /// called after RpcMessage data is written - /// data should be flushed in derived class implementation - virtual void writeMessageEnd() = 0; - /// write bytes to write buffer (and possibly to socket) + /// write fame data to socket /// @return number of writen bytes - virtual int64_t writeBytes(const char *bytes, size_t length) = 0; + virtual int64_t writeFrameData(std::string &&frame_data) = 0; /// call it when new data arrived - virtual void onBytesRead(std::string &&bytes); + virtual void onFrameDataRead(std::string &&frame_data); - /// add data to the output queue, send data from top of the queue - virtual void enqueueDataToSend(MessageData &&chunk_to_enqueue); - - virtual void onRpcDataReceived(Rpc::ProtocolType protocol_type, RpcValue::MetaData &&md, std::string &&data); + virtual void onRpcFrameReceived(RpcFrame &&frame); virtual void onParseDataException(const shv::chainpack::ParseException &e) = 0; - virtual void onRpcValueReceived(const RpcValue &msg); virtual void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) = 0; - - void lockSendQueueGuard(); - void unlockSendQueueGuard(); private: - void processReadData(); - void writeQueue(); - int64_t writeBytes_helper(const std::string &str, size_t from, size_t length); + void processReadFrameData(std::string &&frame_data); private: - std::deque m_sendQueue; - bool m_topMessageDataHeaderWritten = false; - size_t m_topMessageDataBytesWrittenSoFar = 0; - std::string m_readData; - Rpc::ProtocolType m_protocolType = Rpc::ProtocolType::Invalid; static int s_defaultRpcTimeoutMsec; }; diff --git a/libshvchainpack/include/shv/chainpack/rpcmessage.h b/libshvchainpack/include/shv/chainpack/rpcmessage.h index f807a16f3..8228f4fbc 100644 --- a/libshvchainpack/include/shv/chainpack/rpcmessage.h +++ b/libshvchainpack/include/shv/chainpack/rpcmessage.h @@ -13,6 +13,21 @@ namespace chainpack { class AbstractStreamWriter; class TunnelCtl; +class RpcMessage; + +struct SHVCHAINPACK_DECL_EXPORT RpcFrame +{ + Rpc::ProtocolType protocol = Rpc::ProtocolType::ChainPack; + RpcValue::MetaData meta; + std::string data; + + RpcFrame() = default; + RpcFrame(RpcValue::MetaData &&meta, std::string &&data) : meta(std::move(meta)), data(std::move(data)) {} + bool isValid() const { return !meta.isEmpty() && !data.empty(); } + RpcMessage toRpcMessage(std::string *errmsg = nullptr) const; + std::string toChainPack() const; + static RpcFrame fromChainPack(std::string &&frame_data); +}; class SHVCHAINPACK_DECL_EXPORT RpcMessage { @@ -23,14 +38,14 @@ class SHVCHAINPACK_DECL_EXPORT RpcMessage public: enum {ID = meta::GlobalNS::MetaTypeId::ChainPackRpcMessage}; struct Tag { enum Enum {RequestId = meta::Tag::USER, // 8 - ShvPath, // 9 - Method, // 10 - CallerIds, // 11 - ProtocolType, //needed when dest client is using different version than source one to translate raw message data to correct format - RevCallerIds, - AccessGrant, - TunnelCtl, - UserId, + ShvPath = 9, // 9 + Method = 10, // 10 + CallerIds = 11, // 11 + //ProtocolType, //needed when dest client is using different version than source one to translate raw message data to correct format + RevCallerIds = 13, + AccessGrant = 14, + TunnelCtl = 15, + UserId = 16, MAX};}; struct Key { enum Enum {Params = 1, Result, Error, MAX};}; @@ -111,13 +126,16 @@ class SHVCHAINPACK_DECL_EXPORT RpcMessage static RpcValue userId(RpcValue::MetaData &meta); static void setUserId(RpcValue::MetaData &meta, const RpcValue &user_id); - static Rpc::ProtocolType protocolType(const RpcValue::MetaData &meta); - static void setProtocolType(RpcValue::MetaData &meta, shv::chainpack::Rpc::ProtocolType ver); - Rpc::ProtocolType protocolType() const; - void setProtocolType(shv::chainpack::Rpc::ProtocolType ver); + //static Rpc::ProtocolType protocolType(const RpcValue::MetaData &meta); + //static void setProtocolType(RpcValue::MetaData &meta, shv::chainpack::Rpc::ProtocolType ver); + //Rpc::ProtocolType protocolType() const; + //void setProtocolType(shv::chainpack::Rpc::ProtocolType ver); std::string toPrettyString() const; std::string toCpon() const; + std::string toChainPack() const; + + RpcFrame toToRpcFrame() const; const RpcValue::MetaData& metaData() const; RpcValue metaValue(RpcValue::Int key) const; diff --git a/libshvchainpack/include/shv/chainpack/rpcvalue.h b/libshvchainpack/include/shv/chainpack/rpcvalue.h index 9454e43bd..881920b81 100644 --- a/libshvchainpack/include/shv/chainpack/rpcvalue.h +++ b/libshvchainpack/include/shv/chainpack/rpcvalue.h @@ -411,6 +411,7 @@ class SHVCHAINPACK_DECL_EXPORT RpcValue void append(const RpcValue &val); RpcValue metaStripped() const; + MetaData stripMeta(); std::string toPrettyString(const std::string &indent = std::string()) const; std::string toStdString() const; diff --git a/libshvchainpack/include/shv/chainpack/socketrpcdriver.h b/libshvchainpack/include/shv/chainpack/socketrpcdriver.h index c6b7b3c7a..e7216ad28 100644 --- a/libshvchainpack/include/shv/chainpack/socketrpcdriver.h +++ b/libshvchainpack/include/shv/chainpack/socketrpcdriver.h @@ -21,9 +21,7 @@ class SHVCHAINPACK_DECL_EXPORT SocketRpcDriver : public RpcDriver void sendNotify(std::string &&method, const RpcValue &result); protected: bool isOpen() override; - void writeMessageBegin() override; - void writeMessageEnd() override; - int64_t writeBytes(const char *bytes, size_t length) override; + int64_t writeFrameData(std::string &&frame_data) override; virtual void idleTaskOnSelectTimeout(); private: @@ -33,6 +31,8 @@ class SHVCHAINPACK_DECL_EXPORT SocketRpcDriver : public RpcDriver int m_socket = -1; std::string m_writeBuffer; size_t m_maxWriteBufferLength = 1024; + std::string m_readBuffer; + size_t m_readFrameSize = 0; }; }} diff --git a/libshvchainpack/src/chainpack/rpc.cpp b/libshvchainpack/src/chainpack/rpc.cpp index f2925b3d6..edb6ad00d 100644 --- a/libshvchainpack/src/chainpack/rpc.cpp +++ b/libshvchainpack/src/chainpack/rpc.cpp @@ -6,8 +6,6 @@ const char *Rpc::protocolTypeToString(Rpc::ProtocolType pv) { switch(pv) { case ProtocolType::ChainPack: return "ChainPack"; - case ProtocolType::Cpon: return "Cpon"; - case ProtocolType::JsonRpc: return "JsonRpc"; case ProtocolType::Invalid: return "Invalid"; } return "???"; diff --git a/libshvchainpack/src/chainpack/rpcdriver.cpp b/libshvchainpack/src/chainpack/rpcdriver.cpp index b748333c7..66791d3e5 100644 --- a/libshvchainpack/src/chainpack/rpcdriver.cpp +++ b/libshvchainpack/src/chainpack/rpcdriver.cpp @@ -19,6 +19,8 @@ #define logWriteQueue() nCMessage("WriteQueue") #define logWriteQueueW() nCWarning("WriteQueue") +using namespace std; + namespace shv::chainpack { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) @@ -28,201 +30,30 @@ RpcDriver::RpcDriver() = default; RpcDriver::~RpcDriver() = default; -Rpc::ProtocolType RpcDriver::protocolType() const -{ - return m_protocolType; -} - -void RpcDriver::setProtocolType(Rpc::ProtocolType v) -{ - m_protocolType = v; -} - -void RpcDriver::sendRpcValue(const RpcValue &msg) +void RpcDriver::sendRpcMessage(const RpcMessage &msg) { using namespace std; logRpcRawMsg() << SND_LOG_ARROW << msg.toPrettyString(); - std::string packed_data = codeRpcValue(protocolType(), msg); - logRpcData() << "SEND protocol:" << Rpc::protocolTypeToString(protocolType()) - << "packed data:" - << ((protocolType() == Rpc::ProtocolType::ChainPack)? Utils::toHex(packed_data, 0, 250): packed_data.substr(0, 250)); - enqueueDataToSend(MessageData{std::move(packed_data)}); + auto frame_data = msg.toChainPack(); + logRpcData() << "SEND data:" << Utils::toHex(frame_data, 0, 250); + writeFrameData(std::move(frame_data)); } -void RpcDriver::sendRawData(std::string &&data) +void RpcDriver::sendRpcFrame(RpcFrame &&frame) { - logRpcRawMsg() << SND_LOG_ARROW << "send raw data: " << (data.size() > 250? "<... long data ...>" : Utils::toHex(data)); - enqueueDataToSend(MessageData{std::move(data)}); + logRpcRawMsg() << SND_LOG_ARROW + << "protocol:" << Rpc::protocolTypeToString(frame.protocol) + << "send raw meta + data: " << frame.meta.toPrettyString() + << Utils::toHex(frame.data, 0, 250); + auto frame_data = frame.toChainPack(); + logRpcData() << "SEND data:" << Utils::toHex(frame_data, 0, 250); + writeFrameData(std::move(frame_data)); } -void RpcDriver::sendRawData(const RpcValue::MetaData &meta_data, std::string &&data) +void RpcDriver::onFrameDataRead(std::string &&frame_data) { - logRpcRawMsg() << SND_LOG_ARROW << "protocol:" << Rpc::protocolTypeToString(protocolType()) << "send raw meta + data: " << meta_data.toPrettyString() - << Utils::toHex(data, 0, 250); - using namespace std; - std::ostringstream os_packed_meta_data; - switch (protocolType()) { - case Rpc::ProtocolType::Cpon: { - CponWriter wr(os_packed_meta_data); - wr << meta_data; - break; - } - case Rpc::ProtocolType::ChainPack: { - ChainPackWriter wr(os_packed_meta_data); - wr << meta_data; - break; - } - case Rpc::ProtocolType::JsonRpc: { - break; - } - default: - SHVCHP_EXCEPTION("Cannot serialize data without protocol version specified."); - } - Rpc::ProtocolType packed_data_ver = RpcMessage::protocolType(meta_data); - if(protocolType() == Rpc::ProtocolType::JsonRpc) { - // JSON RPC must be handled separately - if(packed_data_ver == Rpc::ProtocolType::Invalid) - SHVCHP_EXCEPTION("Cannot serialize to JSON-RPC data without protocol version specified."); - // recode data; - RpcValue val = decodeData(packed_data_ver, data, 0); - val.setMetaData(RpcValue::MetaData(meta_data)); - enqueueDataToSend(MessageData(codeRpcValue(Rpc::ProtocolType::JsonRpc, val))); - } - else { - if(packed_data_ver == Rpc::ProtocolType::Invalid || packed_data_ver == protocolType()) { - enqueueDataToSend(MessageData(os_packed_meta_data.str(), std::move(data))); - } - else { - // recode data; - RpcValue val = decodeData(packed_data_ver, data, 0); - enqueueDataToSend(MessageData(os_packed_meta_data.str(), codeRpcValue(protocolType(), val))); - } - } -} - -RpcMessage RpcDriver::composeRpcMessage(RpcValue::MetaData &&meta_data, const std::string &data, std::string *errmsg) -{ - Rpc::ProtocolType protocol_type = RpcMessage::protocolType(meta_data); - RpcValue val = decodeData(protocol_type, data, 0); - if(!val.isValid()) { - const char * msg = "Compose RPC message error."; - if(!errmsg) { - SHVCHP_EXCEPTION(msg); - } - - *errmsg = msg; - return RpcMessage(); - } - val.setMetaData(std::move(meta_data)); - return RpcMessage(val); -} - -void RpcDriver::enqueueDataToSend(RpcDriver::MessageData &&chunk_to_enqueue) -{ - /// LOCK_FOR_SEND lock mutex here in the multithreaded environment - lockSendQueueGuard(); - if(!chunk_to_enqueue.empty()) { - m_sendQueue.push_back(std::move(chunk_to_enqueue)); - logWriteQueue() << "===========> write chunk added, new queue len:" << m_sendQueue.size(); - } - writeQueue(); - /// UNLOCK_FOR_SEND unlock mutex here in the multithreaded environment - unlockSendQueueGuard(); -} - -void RpcDriver::writeQueue() -{ - if(m_sendQueue.empty()) - return; - logWriteQueue() << "writeQueue(), queue len:" << m_sendQueue.size(); - if(!isOpen()) { - nError() << "write data error, socket is not open!"; - return; - } - const MessageData &chunk = m_sendQueue[0]; - logWriteQueue() << "chunk size:" << chunk.size() << "meta:" << chunk.metaData.size() << "data:" << chunk.data.size(); - if(!m_topMessageDataHeaderWritten) { - writeMessageBegin(); - std::string protocol_type_data; - { - std::ostringstream os; - { ChainPackWriter wr(os); wr.writeUIntData(static_cast(protocolType()));} - protocol_type_data = os.str(); - } - { - std::ostringstream os; - { ChainPackWriter wr(os); wr.writeUIntData(chunk.size() + protocol_type_data.length()); } - std::string packet_len_data = os.str(); - auto len = writeBytes(packet_len_data.data(), packet_len_data.length()); - if(len < 0) - SHVCHP_EXCEPTION("Write socket error!"); - if(len < static_cast(packet_len_data.length())) - SHVCHP_EXCEPTION("Design error! Chunk length shall be always written at once to the socket"); - } - { - auto len = writeBytes(protocol_type_data.data(), protocol_type_data.length()); - logWriteQueue() << "\twrite header len:" << len; - if(len < 0) - SHVCHP_EXCEPTION("Write socket error!"); - if(len != 1) - SHVCHP_EXCEPTION("Design error! Protocol version shall be always written at once to the socket"); - } - m_topMessageDataHeaderWritten = true; - } - if(m_topMessageDataBytesWrittenSoFar < chunk.metaData.size()) { - auto len = writeBytes_helper(chunk.metaData, m_topMessageDataBytesWrittenSoFar, chunk.metaData.size() - m_topMessageDataBytesWrittenSoFar); - logWriteQueue() << "\twrite metadata len:" << len; - m_topMessageDataBytesWrittenSoFar += static_cast(len); - } - if(m_topMessageDataBytesWrittenSoFar >= chunk.metaData.size()) { - auto len = writeBytes_helper(chunk.data - , m_topMessageDataBytesWrittenSoFar - chunk.metaData.size() - , chunk.data.size() - (m_topMessageDataBytesWrittenSoFar - chunk.metaData.size())); - logWriteQueue() << "\twrite data len:" << len; - m_topMessageDataBytesWrittenSoFar += static_cast(len); - } - logWriteQueue() << "----- bytes written so far:" << m_topMessageDataBytesWrittenSoFar - << "remaining:" << (chunk.size() - m_topMessageDataBytesWrittenSoFar) - << "queue len:" << m_sendQueue.size(); - if(m_topMessageDataBytesWrittenSoFar == chunk.size()) { - m_topMessageDataHeaderWritten = false; - m_topMessageDataBytesWrittenSoFar = 0; - m_sendQueue.pop_front(); - writeMessageEnd(); - logWriteQueue() << "<=========== write chunk finished, new queue len:" << m_sendQueue.size(); - } -} - -int64_t RpcDriver::writeBytes_helper(const std::string &str, size_t from, size_t length) -{ - if(length == 0) - SHVCHP_EXCEPTION("Design error! Atempt to write empty buffer to the socket"); - auto len = writeBytes(str.data() + from, length); - if(len < 0) - SHVCHP_EXCEPTION("Write socket error!"); - if(len == 0) - SHVCHP_EXCEPTION("Design error! At least 1 byte of data shall be always written to the socket"); - return len; -} - -void RpcDriver::onBytesRead(std::string &&bytes) -{ - logRpcData().nospace() << __FUNCTION__ << " " << bytes.length() << " bytes of data read:\n" << shv::chainpack::Utils::hexDump(bytes); - m_readData += bytes; - while(true) { - auto old_len = m_readData.size(); - processReadData(); - if(old_len == m_readData.size()) - break; - } -} - -void RpcDriver::clearSendBuffers() -{ - m_sendQueue.clear(); - m_topMessageDataHeaderWritten = false; - m_topMessageDataBytesWrittenSoFar = 0; - m_readData.clear(); + logRpcData().nospace() << __FUNCTION__ << " " << frame_data.length() << " bytes of data read:\n" << shv::chainpack::Utils::hexDump(frame_data); + processReadFrameData(std::move(frame_data)); } int RpcDriver::defaultRpcTimeoutMsec() @@ -235,340 +66,46 @@ void RpcDriver::setDefaultRpcTimeoutMsec(int msec) s_defaultRpcTimeoutMsec = msec; } -void RpcDriver::processReadData() +void RpcDriver::processReadFrameData(std::string &&frame_data) { logRpcData() << __PRETTY_FUNCTION__ << "+++++++++++++++++++++++++++++++++"; using namespace shv::chainpack; - size_t message_len; - Rpc::ProtocolType protocol_type; - RpcValue::MetaData meta_data; - size_t meta_data_end_pos = 0; - while (!m_readData.empty()) { - logRpcData().nospace() << "READ DATA " << m_readData.length() << " bytes of data read:\n" << shv::chainpack::Utils::hexDump(m_readData); - const std::string &read_data = m_readData; - try { - // read header and metadata - std::istringstream in(read_data); - int err_code; - uint64_t chunk_len = ChainPackReader::readUIntData(in, &err_code); - if(err_code == CCPCP_RC_BUFFER_UNDERFLOW) { - // not enough data - logRpcData() << "msg len not complete"; - return; - } - if(err_code != CCPCP_RC_OK) { - throw ParseException(err_code, "Read RPC message length error.", -1); - } - - message_len = static_cast(in.tellg()) + chunk_len; - protocol_type = static_cast(ChainPackReader::readUIntData(in, &err_code)); - if(err_code == CCPCP_RC_BUFFER_UNDERFLOW) { - // not enough data - logRpcData() << "protocol_type not complete"; - return; - } - if(err_code != CCPCP_RC_OK) { - throw ParseException(err_code, "Read RPC message protocol type error.", -1); - } - - if(in.tellg() < 0) { - // end of stream - return; - } - - logRpcData() << "\t protocol_type:" << static_cast(protocol_type) << Rpc::protocolTypeToString(protocol_type); - logRpcData() << "\t expected message data length:" << message_len << "length available:" << read_data.size(); - // wait for complete message - if(message_len > read_data.length()) - return; - - meta_data_end_pos = decodeMetaData(meta_data, protocol_type, read_data, static_cast(in.tellg())); - logRpcData() << "\t meta_data_end_pos:" << meta_data_end_pos << meta_data.toPrettyString(); - if(meta_data_end_pos > message_len) - throw ParseException(CCPCP_RC_MALFORMED_INPUT, "Metadata length mismatch", -1); - } - catch (const ParseException &e) { - if(e.errCode() == CCPCP_RC_BUFFER_UNDERFLOW) { - // not enough data - return; - } - logRpcDataW() << "ERROR - RpcMessage header corrupted:" << e.msg(); - logRpcDataW() << "The error occured in data:\n" << shv::chainpack::utils::hexDump(m_readData.data(), 1024); - onParseDataException(e); - return; - } - - if(m_protocolType == Rpc::ProtocolType::Invalid && protocol_type != Rpc::ProtocolType::Invalid) { - // if protocol version is not explicitly specified, - // it is set from first received message - m_protocolType = protocol_type; - } - - assert(meta_data_end_pos > 0); - std::string msg_data; - try { - msg_data = read_data.substr(meta_data_end_pos, message_len - meta_data_end_pos); - logRpcData() << message_len << "bytes of" << m_readData.size() << "processed"; - m_readData = m_readData.substr(message_len); - } - catch (const std::exception &e) { - nError() << "internal exception:" << e.what(); - } - try { - onRpcDataReceived(protocol_type, std::move(meta_data), std::move(msg_data)); - } - catch (const std::exception &e) { - nError() << "onRpcDataReceived exception:" << e.what(); - } - return; - } -} - -size_t RpcDriver::decodeMetaData(RpcValue::MetaData &meta_data, Rpc::ProtocolType protocol_type, const std::string &data, size_t start_pos) -{ - size_t meta_data_end_pos = start_pos; - std::istringstream in(data); - in.seekg(static_cast(start_pos)); - - switch (protocol_type) { - case Rpc::ProtocolType::JsonRpc: { - CponReader rd(in); - RpcValue msg; - rd.read(msg); - if(!msg.isMap()) { - throw ParseException(CCPCP_RC_MALFORMED_INPUT, "JSON message cannot be translated to ChainPack", -1); - } - - const RpcValue::Map &map = msg.asMap(); - int id = map.value(Rpc::JSONRPC_REQUEST_ID).toInt(); - int caller_id = map.value(Rpc::JSONRPC_CALLER_ID).toInt(); - RpcValue::String method = map.value(Rpc::JSONRPC_METHOD).toString(); - std::string shv_path = map.value(Rpc::JSONRPC_SHV_PATH).toString(); - if(id > 0) - RpcMessage::setRequestId(meta_data, id); - if(!method.empty()) - RpcMessage::setMethod(meta_data, method); - if(!shv_path.empty()) - RpcMessage::setShvPath(meta_data, shv_path); - if(caller_id > 0) - RpcMessage::setCallerIds(meta_data, caller_id); - break; - } - case Rpc::ProtocolType::Cpon: { - CponReader rd(in); - rd.read(meta_data); - meta_data_end_pos = (in.tellg() < 0)? data.size(): static_cast(in.tellg()); - if(meta_data_end_pos == start_pos) - throw ParseException(CCPCP_RC_MALFORMED_INPUT, "Metadata missing", -1); - break; - } - case Rpc::ProtocolType::ChainPack: { - ChainPackReader rd(in); - rd.read(meta_data); - meta_data_end_pos = (in.tellg() < 0)? data.size(): static_cast(in.tellg()); - if(meta_data_end_pos == start_pos) - throw ParseException(CCPCP_RC_MALFORMED_INPUT, "Metadata missing", -1); - break; - } - default: - throw ParseException(CCPCP_RC_MALFORMED_INPUT, "Unknown protocol type: " + Utils::toString(static_cast(protocol_type)), -1); - } - - return meta_data_end_pos; -} - -RpcValue RpcDriver::decodeData(Rpc::ProtocolType protocol_type, const std::string &data, size_t start_pos) -{ - RpcValue ret; - std::istringstream in(data); - in.seekg(static_cast(start_pos)); + logRpcData().nospace() << "READ DATA " << frame_data.size() << " bytes of data read:\n" << shv::chainpack::Utils::hexDump(frame_data); try { - switch (protocol_type) { - case Rpc::ProtocolType::JsonRpc: { - CponReader rd(in); - rd.read(ret); - RpcValue::Map map = ret.asMap(); - RpcValue::IMap imap; - RpcValue params = map.value(Rpc::JSONRPC_PARAMS); - if(params.isValid()) { - imap[RpcMessage::MetaType::Key::Params] = params; - } - else { - RpcValue result = map.value(Rpc::JSONRPC_RESULT); - if(result.isValid()) { - imap[RpcMessage::MetaType::Key::Result] = result; - } - else { - RpcValue error = map.value(Rpc::JSONRPC_ERROR); - if(error.isValid()) - imap[RpcMessage::MetaType::Key::Error] = RpcResponse::Error::fromJson(error.asMap()).toRpcValue(); - } - } - ret = imap; - break; - } - case Rpc::ProtocolType::Cpon: { - CponReader rd(in); - rd.read(ret); - break; - } - case Rpc::ProtocolType::ChainPack: { - ChainPackReader rd(in); - rd.read(ret); - break; - } - default: - logRpcDataW() << "Don't know how to decode message with unknown protocol version:" << static_cast(protocol_type); - break; - } - } - catch(ParseException &e) { - logRpcDataW() << Rpc::protocolTypeToString(protocol_type) << "Decode data error:" << e.msg(); - auto err_pos = std::min(static_cast(e.pos()), data.size()); - auto hexdump_start_pos = err_pos - std::min(err_pos, static_cast(10*16)); - logRpcDataW().nospace() << "Start offset: " << start_pos << " Data: from pos:" - << hexdump_start_pos << "\n" << shv::chainpack::utils::hexDump(data.data() + hexdump_start_pos, 10*16); + auto frame = RpcFrame::fromChainPack(std::move(frame_data)); + onRpcFrameReceived(std::move(frame)); } - return ret; -} - -std::string RpcDriver::codeRpcValue(Rpc::ProtocolType protocol_type, const RpcValue &val) -{ - std::ostringstream os_packed_data; - switch (protocol_type) { - case Rpc::ProtocolType::JsonRpc: { - RpcValue::Map json_msg; - RpcMessage rpc_msg(val); - - const RpcValue rq_id = rpc_msg.requestId(); - if(rq_id.isValid()) - json_msg[Rpc::JSONRPC_REQUEST_ID] = rq_id; - - const RpcValue shv_path = rpc_msg.shvPath(); - if(shv_path.isString()) - json_msg[Rpc::JSONRPC_SHV_PATH] = shv_path.toString(); - - const RpcValue caller_id = rpc_msg.callerIds(); - if(caller_id.isValid()) - json_msg[Rpc::JSONRPC_CALLER_ID] = caller_id; - ; - if(rpc_msg.isResponse()) { - // response - RpcResponse resp(rpc_msg); - if(resp.isError()) - json_msg[Rpc::JSONRPC_ERROR] = resp.error().toJson(); - else - json_msg[Rpc::JSONRPC_RESULT] = resp.result(); - } - else { - // request - RpcRequest rq(rpc_msg); - json_msg[Rpc::JSONRPC_METHOD] = rq.method(); - if(rq.params().isValid()) - json_msg[Rpc::JSONRPC_PARAMS] = rq.params(); - } - CponWriterOptions opts; - opts.setJsonFormat(true); - CponWriter wr(os_packed_data, opts); - wr.write(json_msg); - break; - } - case Rpc::ProtocolType::Cpon: { - CponWriter wr(os_packed_data); - wr << val; - break; - } - case Rpc::ProtocolType::ChainPack: { - ChainPackWriter wr(os_packed_data); - wr << val; - break; + catch (const ParseException &e) { + logRpcDataW() << "ERROR - RpcMessage header corrupted:" << e.msg(); + //logRpcDataW() << "The error occured in data:\n" << shv::chainpack::utils::hexDump(m_readData.data(), 1024); + onParseDataException(e); + return; } - default: - SHVCHP_EXCEPTION("Cannot serialize data without protocol version specified."); + catch (const std::exception &e) { + nError() << "processReadFrameData exception:" << e.what(); } - return os_packed_data.str(); } -void RpcDriver::onRpcDataReceived(Rpc::ProtocolType protocol_type, RpcValue::MetaData &&md, std::string &&data) +void RpcDriver::onRpcFrameReceived(RpcFrame &&frame) { - RpcValue msg = decodeData(protocol_type, data, 0); - if(msg.isValid()) { - msg.setMetaData(std::move(md)); - logRpcRawMsg() << RCV_LOG_ARROW << msg.toPrettyString(); - onRpcValueReceived(msg); - } - else { - nError() << "Throwing away invalid or empty message"; - } -} - -void RpcDriver::onRpcValueReceived(const RpcValue &rpc_val) -{ - logRpcData() << "\t message received:" << rpc_val.toCpon(); - RpcMessage msg(rpc_val); + auto msg = frame.toRpcMessage(); onRpcMessageReceived(msg); - } -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -static int lock_cnt = 0; -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -static int logged_lock_cnt = 0; -void RpcDriver::lockSendQueueGuard() -{ - lock_cnt++; - if(lock_cnt != 1) { - if(logged_lock_cnt != lock_cnt) { - logged_lock_cnt = lock_cnt; - logWriteQueueW() << "Invalid write queue lock count:" << lock_cnt; - } - } -} - -void RpcDriver::unlockSendQueueGuard() -{ - lock_cnt--; -} - -std::string RpcDriver::dataToPrettyCpon(Rpc::ProtocolType protocol_type, const RpcValue::MetaData &md, const std::string &data, size_t start_pos, size_t data_len) +std::string RpcDriver::frameToPrettyCpon(const RpcFrame &frame) { shv::chainpack::RpcValue rpc_val; - if(data_len == 0) - data_len = data.size() - start_pos; - if(data_len < 256) { - rpc_val = shv::chainpack::RpcDriver::decodeData(protocol_type, data, start_pos); + if(frame.data.length() < 256) { + string errmsg; + auto msg = frame.toRpcMessage(&errmsg); + return msg.toCpon(); } else { - rpc_val = " ... " + std::to_string(data_len) + " bytes of data ... "; + auto s = frame.meta.toPrettyString(); + s += " ... " + std::to_string(frame.data.size()) + " bytes of data ... "; + return s; } - rpc_val.setMetaData(shv::chainpack::RpcValue::MetaData(md)); - return rpc_val.toPrettyString(); -} - -RpcDriver::MessageData::MessageData() = default; - -RpcDriver::MessageData::MessageData(std::string &&meta_data_, std::string &&data_) - : metaData(std::move(meta_data_)), data(std::move(data_)) -{ } -RpcDriver::MessageData::MessageData(std::string &&data_) - : data(std::move(data_)) -{ -} - -RpcDriver::MessageData::MessageData(MessageData &&) noexcept = default; - -bool RpcDriver::MessageData::empty() const -{ - return metaData.empty() && data.empty(); -} - -size_t RpcDriver::MessageData::size() const -{ - return metaData.size() + data.size(); -} - - } // namespace shv diff --git a/libshvchainpack/src/chainpack/rpcmessage.cpp b/libshvchainpack/src/chainpack/rpcmessage.cpp index e1ff64385..75b63c5f0 100644 --- a/libshvchainpack/src/chainpack/rpcmessage.cpp +++ b/libshvchainpack/src/chainpack/rpcmessage.cpp @@ -1,11 +1,15 @@ #include + #include #include #include #include #include +#include +#include #include +#include namespace shv::chainpack { @@ -22,7 +26,7 @@ RpcMessage::MetaType::MetaType() {static_cast(Tag::ShvPath), {static_cast(Tag::ShvPath), Rpc::PAR_PATH}}, {static_cast(Tag::Method), {static_cast(Tag::Method), Rpc::PAR_METHOD}}, {static_cast(Tag::CallerIds), {static_cast(Tag::CallerIds), "cid"}}, - {static_cast(Tag::ProtocolType), {static_cast(Tag::ProtocolType), "protocol"}}, + //{static_cast(Tag::ProtocolType), {static_cast(Tag::ProtocolType), "protocol"}}, {static_cast(Tag::RevCallerIds), {static_cast(Tag::RevCallerIds), "rcid"}}, {static_cast(Tag::AccessGrant), {static_cast(Tag::AccessGrant), "grant"}}, {static_cast(Tag::TunnelCtl), {static_cast(Tag::TunnelCtl), "tctl"}}, @@ -40,6 +44,47 @@ void RpcMessage::MetaType::registerMetaType() } } +//================================================================== +// RpcFrame +//================================================================== +RpcMessage RpcFrame::toRpcMessage(std::string *errmsg) const +{ + auto val = RpcValue::fromChainPack(data, errmsg); + if (!errmsg || (errmsg && errmsg->empty())) { + auto m = meta; + val.setMetaData(std::move(m)); + return RpcMessage(val); + } + return {}; +} + +std::string RpcFrame::toChainPack() const +{ + std::ostringstream out; + { + ChainPackWriter wr(out); + wr << meta; + } + auto ret = out.str(); + ret += data; + return ret; +} + +RpcFrame RpcFrame::fromChainPack(std::string &&frame_data) +{ + std::istringstream in(frame_data); + ChainPackReader rd(in); + RpcValue::MetaData meta; + rd.read(meta); + if(meta.isEmpty()) + throw ParseException(CCPCP_RC_MALFORMED_INPUT, "Metadata missing", -1); + auto pos = in.tellg(); + if(pos < 0) + throw ParseException(CCPCP_RC_MALFORMED_INPUT, "Metadata missing", -1); + auto data = std::string(std::move(frame_data), pos); + return RpcFrame(std::move(meta), std::move(data)); +} + //================================================================== // RpcMessage //================================================================== @@ -422,7 +467,7 @@ void RpcMessage::setUserId(RpcValue::MetaData &meta, const RpcValue &user_id) { meta.setValue(RpcMessage::MetaType::Tag::UserId, user_id); } - +/* Rpc::ProtocolType RpcMessage::protocolType(const RpcValue::MetaData &meta) { return static_cast(meta.value(RpcMessage::MetaType::Tag::ProtocolType).toUInt()); @@ -442,7 +487,7 @@ void RpcMessage::setProtocolType(Rpc::ProtocolType ver) { setMetaValue(RpcMessage::MetaType::Tag::ProtocolType, ver == Rpc::ProtocolType::Invalid? RpcValue(): RpcValue(static_cast(ver))); } - +*/ void RpcMessage::write(AbstractStreamWriter &wr) const { assert(m_value.isValid()); @@ -477,6 +522,19 @@ std::string RpcMessage::toCpon() const return m_value.toCpon(); } +std::string RpcMessage::toChainPack() const +{ + return m_value.toChainPack(); +} + +RpcFrame RpcMessage::toToRpcFrame() const +{ + auto val = m_value; + auto meta = val.stripMeta(); + auto data = val.toChainPack(); + return RpcFrame {std::move(meta), std::move(data)}; +} + //================================================================== // RpcRequest //================================================================== @@ -797,4 +855,5 @@ RpcResponse& RpcResponse::setRequestId(const RpcValue &id) return *this; } + } // namespace shv diff --git a/libshvchainpack/src/chainpack/rpcvalue.cpp b/libshvchainpack/src/chainpack/rpcvalue.cpp index d0b2338d2..2c80d359d 100644 --- a/libshvchainpack/src/chainpack/rpcvalue.cpp +++ b/libshvchainpack/src/chainpack/rpcvalue.cpp @@ -11,12 +11,10 @@ #include -#include #include #include #include #include -#include #include #ifdef DEBUG_RPCVAL @@ -65,7 +63,7 @@ class RpcValue::AbstractValueData virtual void append(const RpcValue &); virtual std::string toStdString() const = 0; - virtual void stripMeta() = 0; + virtual RpcValue::MetaData stripMeta() = 0; virtual AbstractValueData* copy() = 0; }; @@ -154,10 +152,15 @@ class ValueData : public RpcValue::AbstractValueData return tmp; } - void stripMeta() override + RpcValue::MetaData stripMeta() override { - delete m_metaData; - m_metaData = nullptr; + if (m_metaData) { + auto ret = *m_metaData; + delete m_metaData; + m_metaData = nullptr; + return ret; + } + return {}; } protected: @@ -730,6 +733,11 @@ RpcValue RpcValue::metaStripped() const return ret; } +RpcValue::MetaData RpcValue::stripMeta() +{ + return m_ptr->stripMeta(); +} + std::string RpcValue::toPrettyString(const std::string &indent) const { if(isValid()) { diff --git a/libshvchainpack/src/chainpack/socketrpcdriver.cpp b/libshvchainpack/src/chainpack/socketrpcdriver.cpp index 05dbf908c..a2075f4c5 100644 --- a/libshvchainpack/src/chainpack/socketrpcdriver.cpp +++ b/libshvchainpack/src/chainpack/socketrpcdriver.cpp @@ -1,4 +1,6 @@ #include + +#include #include #include @@ -47,31 +49,24 @@ bool SocketRpcDriver::isOpen() return isOpenImpl(); } -void SocketRpcDriver::writeMessageBegin() -{ -} - -void SocketRpcDriver::writeMessageEnd() -{ - flush(); -} - void SocketRpcDriver::idleTaskOnSelectTimeout() { } -int64_t SocketRpcDriver::writeBytes(const char *bytes, size_t length) +int64_t SocketRpcDriver::writeFrameData(std::string &&frame_data) { if(!isOpen()) { nInfo() << "Write to closed socket"; return 0; } flush(); - auto bytes_to_write_len = static_cast((m_writeBuffer.size() + length > m_maxWriteBufferLength)? m_maxWriteBufferLength - m_writeBuffer.size(): length); - if(bytes_to_write_len > 0) - m_writeBuffer += std::string(bytes, static_cast(bytes_to_write_len)); - flush(); - return bytes_to_write_len; + if (m_writeBuffer.size() + frame_data.size() < m_maxWriteBufferLength) { + auto sz = frame_data.size(); + m_writeBuffer += std::move(frame_data); + flush(); + return sz; + } + return -1; } bool SocketRpcDriver::flush() @@ -139,7 +134,7 @@ void SocketRpcDriver::exec() fd_set read_flags,write_flags; // the flag sets to be used struct timeval waitd; - static constexpr size_t BUFF_LEN = 255; + static constexpr size_t BUFF_LEN = 1024; std::array in; std::array out; memset(in.data(), 0, BUFF_LEN); @@ -183,14 +178,47 @@ void SocketRpcDriver::exec() closeConnection(); return; } - onBytesRead(std::string(in.data(), static_cast(n))); + { + m_readBuffer += std::string(in.data(), n); + while (true) { + if (m_readFrameSize == 0) { + // read length + std::istringstream in2(m_readBuffer); + int err_code; + uint64_t frame_size = ChainPackReader::readUIntData(in2, &err_code); + if(err_code == CCPCP_RC_BUFFER_UNDERFLOW) { + // not enough data + break; + } + else if(err_code == CCPCP_RC_OK) { + auto consumed_len = in2.tellg(); + m_readBuffer = std::string(std::move(m_readBuffer), consumed_len); + m_readFrameSize = frame_size; + } + else { + nWarning() << "Read RPC message length error."; + m_readBuffer.clear(); + m_readFrameSize = 0; + break; + } + } + if (m_readFrameSize > 0 && m_readFrameSize <= m_readBuffer.size()) { + auto frame = std::string(m_readBuffer, 0, m_readFrameSize); + m_readBuffer = std::string(std::move(m_readBuffer), m_readFrameSize); + onFrameDataRead(std::move(frame)); + } + if (m_readFrameSize == 0 || m_readFrameSize > m_readBuffer.size()) { + break; + } + } + } } //socket ready for writing if(FD_ISSET(m_socket, &write_flags)) { nInfo() << "\t write fd is set"; FD_CLR(m_socket, &write_flags); - enqueueDataToSend(MessageData()); + flush(); // trigger write next frame in driver } } } @@ -201,7 +229,7 @@ void SocketRpcDriver::sendResponse(int request_id, const cp::RpcValue &result) resp.setRequestId(request_id); resp.setResult(result); nInfo() << "sending response:" << resp.toCpon(); - sendRpcValue(resp.value()); + sendRpcMessage(resp.value()); } void SocketRpcDriver::sendNotify(std::string &&method, const cp::RpcValue &result) @@ -210,7 +238,7 @@ void SocketRpcDriver::sendNotify(std::string &&method, const cp::RpcValue &resul cp::RpcSignal ntf; ntf.setMethod(std::move(method)); ntf.setParams(result); - sendRpcValue(ntf.value()); + sendRpcMessage(ntf.value()); } } diff --git a/libshviotqt/include/shv/iotqt/node/shvnode.h b/libshviotqt/include/shv/iotqt/node/shvnode.h index d4e6f18bb..8146d4465 100644 --- a/libshviotqt/include/shv/iotqt/node/shvnode.h +++ b/libshviotqt/include/shv/iotqt/node/shvnode.h @@ -63,7 +63,7 @@ class SHVIOTQT_DECL_EXPORT ShvNode : public QObject bool isRootNode() const; - virtual void handleRawRpcRequest(chainpack::RpcValue::MetaData &&meta, std::string &&data); + virtual void handleRpcFrame(chainpack::RpcFrame &&frame); virtual void handleRpcRequest(const chainpack::RpcRequest &rq); virtual chainpack::RpcValue handleRpcRequestImpl(const chainpack::RpcRequest &rq); virtual chainpack::RpcValue processRpcRequest(const shv::chainpack::RpcRequest &rq); diff --git a/libshviotqt/include/shv/iotqt/rpc/clientappclioptions.h b/libshviotqt/include/shv/iotqt/rpc/clientappclioptions.h index b461ed7c7..9bdffeeea 100644 --- a/libshviotqt/include/shv/iotqt/rpc/clientappclioptions.h +++ b/libshviotqt/include/shv/iotqt/rpc/clientappclioptions.h @@ -22,8 +22,6 @@ class SHVIOTQT_DECL_EXPORT ClientAppCliOptions : public shv::core::utils::Config CLIOPTION_GETTER_SETTER2(std::string, "server.host", s, setS, erverHost) CLIOPTION_GETTER_SETTER2(bool, "server.peerVerify", s, setS, erverPeerVerify) - CLIOPTION_GETTER_SETTER2(std::string, "rpc.protocolType", p, setP, rotocolType) - CLIOPTION_GETTER_SETTER2(int, "rpc.rpcTimeout", r, setR, pcTimeout) CLIOPTION_GETTER_SETTER2(int, "rpc.reconnectInterval", r, setR, econnectInterval) CLIOPTION_GETTER_SETTER2(int, "rpc.heartbeatInterval", h, setH, eartBeatInterval) diff --git a/libshviotqt/include/shv/iotqt/rpc/clientconnection.h b/libshviotqt/include/shv/iotqt/rpc/clientconnection.h index 9c526d6b7..b3cf08809 100644 --- a/libshviotqt/include/shv/iotqt/rpc/clientconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/clientconnection.h @@ -73,7 +73,7 @@ class SHVIOTQT_DECL_EXPORT ClientConnection : public SocketRpcConnection protected: bool isShvPathMutedInLog(const std::string &shv_path, const std::string &method) const; public: - /// AbstractRpcConnection interface implementation + /// IRpcConnection interface implementation void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) override; void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) override; static QUrl connectionUrlFromString(const QString &url_str); diff --git a/libshviotqt/include/shv/iotqt/rpc/serverconnection.h b/libshviotqt/include/shv/iotqt/rpc/serverconnection.h index c69feced6..05d472bb3 100644 --- a/libshviotqt/include/shv/iotqt/rpc/serverconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/serverconnection.h @@ -46,10 +46,9 @@ class SHVIOTQT_DECL_EXPORT ServerConnection : public SocketRpcConnection Q_SIGNAL void rpcMessageReceived(const shv::chainpack::RpcMessage &msg); - void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) override; void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) override; protected: - void onRpcDataReceived(shv::chainpack::Rpc::ProtocolType protocol_type, shv::chainpack::RpcValue::MetaData &&md, std::string &&msg_data) override; + void onRpcFrameReceived(chainpack::RpcFrame &&frame) override; bool isLoginPhase() const; void processLoginPhase(const chainpack::RpcMessage &msg); diff --git a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h index 08a9b4da3..58a2fb4c5 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h @@ -27,15 +27,13 @@ class SHVIOTQT_DECL_EXPORT SocketRpcConnection : public QObject, public shv::cha void setSocket(Socket *socket); bool hasSocket() const; - void setProtocolTypeAsInt(int v); void connectToHost(const QUrl &url); - Q_SLOT void sendRpcValue(const shv::chainpack::RpcValue &rpc_val); + void sendRpcMessage(const chainpack::RpcMessage &rpc_msg); void closeSocket(); void abortSocket(); - void clearSendBuffers() override; bool isSocketConnected() const; Q_SIGNAL void socketConnectedChanged(bool is_connected); @@ -49,9 +47,7 @@ class SHVIOTQT_DECL_EXPORT SocketRpcConnection : public QObject, public shv::cha protected: // RpcDriver interface bool isOpen() Q_DECL_OVERRIDE; - int64_t writeBytes(const char *bytes, size_t length) Q_DECL_OVERRIDE; - void writeMessageBegin() override; - void writeMessageEnd() override; + int64_t writeFrameData(std::string &&frame_data) override; Socket* socket(); void onReadyRead(); diff --git a/libshviotqt/src/node/shvnode.cpp b/libshviotqt/src/node/shvnode.cpp index 87e58ac5c..077abdb85 100644 --- a/libshviotqt/src/node/shvnode.cpp +++ b/libshviotqt/src/node/shvnode.cpp @@ -126,18 +126,18 @@ bool ShvNode::isRootNode() const return m_isRootNode; } -void ShvNode::handleRawRpcRequest(RpcValue::MetaData &&meta, std::string &&data) +void ShvNode::handleRpcFrame(RpcFrame &&frame) { - shvLogFuncFrame() << "node:" << nodeId() << "meta:" << meta.toPrettyString(); + shvLogFuncFrame() << "node:" << nodeId() << "meta:" << frame.meta.toPrettyString(); using ShvPath = shv::core::utils::ShvPath; using namespace std; using namespace shv::core::utils; - const chainpack::RpcValue::String method = RpcMessage::method(meta).toString(); - const chainpack::RpcValue::String shv_path_str = RpcMessage::shvPath(meta).toString(); - ShvUrl shv_url(RpcMessage::shvPath(meta).asString()); + const chainpack::RpcValue::String method = RpcMessage::method(frame.meta).toString(); + const chainpack::RpcValue::String shv_path_str = RpcMessage::shvPath(frame.meta).toString(); + ShvUrl shv_url(RpcMessage::shvPath(frame.meta).asString()); core::StringViewList shv_path = ShvPath::split(shv_url.pathPart()); - const bool ls_hook = meta.hasKey(ADD_LOCAL_TO_LS_RESULT_HACK_META_KEY); - RpcResponse resp = RpcResponse::forRequest(meta); + const bool ls_hook = frame.meta.hasKey(ADD_LOCAL_TO_LS_RESULT_HACK_META_KEY); + RpcResponse resp = RpcResponse::forRequest(frame.meta); try { if(!shv_path.empty()) { ShvNode *nd = childNode(std::string{shv_path.at(0)}, !shv::core::Exception::Throw); @@ -147,8 +147,8 @@ void ShvNode::handleRawRpcRequest(RpcValue::MetaData &&meta, std::string &&data) shv_url.service(), shv_url.fullBrokerId(), ShvPath::joinDirs(++shv_path.begin(), shv_path.end())); - RpcMessage::setShvPath(meta, new_path); - nd->handleRawRpcRequest(std::move(meta), std::move(data)); + RpcMessage::setShvPath(frame.meta, new_path); + nd->handleRpcFrame(std::move(frame)); return; } } @@ -156,7 +156,7 @@ void ShvNode::handleRawRpcRequest(RpcValue::MetaData &&meta, std::string &&data) if(mm) { shvDebug() << "Metamethod:" << method << "on path:" << ShvPath::joinDirs(shv_path) << "FOUND"; std::string errmsg; - RpcMessage rpc_msg = RpcDriver::composeRpcMessage(std::move(meta), data, &errmsg); + RpcMessage rpc_msg = frame.toRpcMessage(&errmsg); if(!errmsg.empty()) SHV_EXCEPTION(errmsg); diff --git a/libshviotqt/src/rpc/clientappclioptions.cpp b/libshviotqt/src/rpc/clientappclioptions.cpp index 6c52fcbe0..1049fb3d7 100644 --- a/libshviotqt/src/rpc/clientappclioptions.cpp +++ b/libshviotqt/src/rpc/clientappclioptions.cpp @@ -16,7 +16,6 @@ ClientAppCliOptions::ClientAppCliOptions() addOption("server.host").setType(cp::RpcValue::Type::String).setNames("-s", "--server-host").setComment("server host").setDefaultValue("localhost"); addOption("server.peerVerify").setType(cp::RpcValue::Type::Bool).setNames("--peer-verify").setComment("Verify peer's identity when establishing secured connection").setDefaultValue(true); - addOption("rpc.protocolType").setType(cp::RpcValue::Type::String).setNames("--protocol-type").setComment("Protocol type [chainpack | cpon | jsonrpc]").setDefaultValue("chainpack"); addOption("rpc.rpcTimeout").setType(cp::RpcValue::Type::Int).setNames("--rto", "--rpc-time-out").setComment("Set default RPC calls timeout [sec].").setDefaultValue(shv::chainpack::RpcDriver::defaultRpcTimeoutMsec() / 1000); addOption("rpc.reconnectInterval").setType(cp::RpcValue::Type::Int).setNames("--rci", "--rpc-reconnect-interval").setComment("Reconnect to broker if connection lost at least after recoonect-interval seconds. Disabled when set to 0").setDefaultValue(10); addOption("rpc.heartbeatInterval").setType(cp::RpcValue::Type::Int).setNames("--hbi", "--rpc-heartbeat-interval").setComment("Send heart beat to broker every n sec. Disabled when set to 0").setDefaultValue(60); diff --git a/libshviotqt/src/rpc/clientconnection.cpp b/libshviotqt/src/rpc/clientconnection.cpp index 61da32626..4251737b0 100644 --- a/libshviotqt/src/rpc/clientconnection.cpp +++ b/libshviotqt/src/rpc/clientconnection.cpp @@ -44,8 +44,6 @@ ClientConnection::ClientConnection(QObject *parent) : Super(parent) , m_loginType(IRpcConnection::LoginType::Sha1) { - setProtocolType(shv::chainpack::Rpc::ProtocolType::ChainPack); - connect(this, &SocketRpcConnection::socketConnectedChanged, this, &ClientConnection::onSocketConnectedChanged); m_checkBrokerConnectedTimer = new QTimer(this); @@ -161,14 +159,6 @@ void ClientConnection::setCliOptions(const ClientAppCliOptions *cli_opts) shvInfo() << "Default RPC timeout set to:" << cp::RpcDriver::defaultRpcTimeoutMsec() << "msec."; } - const std::string pv = cli_opts->protocolType(); - if(pv == "cpon") - setProtocolType(shv::chainpack::Rpc::ProtocolType::Cpon); - else if(pv == "jsonrpc") - setProtocolType(shv::chainpack::Rpc::ProtocolType::JsonRpc); - else - setProtocolType(shv::chainpack::Rpc::ProtocolType::ChainPack); - setConnectionString(QString::fromStdString(cli_opts->serverHost())); setPeerVerify(cli_opts->serverPeerVerify()); if(cli_opts->user_isset()) @@ -297,11 +287,10 @@ void ClientConnection::sendMessage(const cp::RpcMessage &rpc_msg) NecroLog::create(NecroLog::Level::Message, NecroLog::LogContext(__FILE__, __LINE__, TOPIC_RPC_MSG)) << SND_LOG_ARROW << "client id:" << connectionId() - << "protocol_type:" << static_cast(protocolType()) << shv::chainpack::Rpc::protocolTypeToString(protocolType()) << std::string_view(m_rawRpcMessageLog? rpc_msg.toCpon(): rpc_msg.toPrettyString()).substr(0, MAX_LOG_LEN); } } - sendRpcValue(rpc_msg.value()); + sendRpcMessage(rpc_msg); } void ClientConnection::onRpcMessageReceived(const chainpack::RpcMessage &rpc_msg) @@ -333,7 +322,6 @@ void ClientConnection::onRpcMessageReceived(const chainpack::RpcMessage &rpc_msg NecroLog::create(NecroLog::Level::Message, NecroLog::LogContext(__FILE__, __LINE__, TOPIC_RPC_MSG)) << cp::RpcDriver::RCV_LOG_ARROW << "client id:" << connectionId() - << "protocol_type:" << static_cast(protocolType()) << shv::chainpack::Rpc::protocolTypeToString(protocolType()) << std::string_view(m_rawRpcMessageLog? rpc_msg.toCpon(): rpc_msg.toPrettyString()).substr(0, MAX_LOG_LEN); } } @@ -425,7 +413,6 @@ void ClientConnection::onSocketConnectedChanged(bool is_connected) shvInfo() << objectName() << "connection id:" << connectionId() << "Socket connected to RPC server"; shvInfo() << "peer:" << peerAddress() << "port:" << peerPort(); setState(State::SocketConnected); - clearSendBuffers(); if(loginType() == LoginType::None) { shvInfo() << "Connection scheme:" << connectionUrl().scheme() << " is skipping login phase."; setState(State::BrokerConnected); diff --git a/libshviotqt/src/rpc/serverconnection.cpp b/libshviotqt/src/rpc/serverconnection.cpp index ddf62e8d0..703c9bf51 100644 --- a/libshviotqt/src/rpc/serverconnection.cpp +++ b/libshviotqt/src/rpc/serverconnection.cpp @@ -93,21 +93,14 @@ bool ServerConnection::isSlaveBrokerConnection() const return m_connectionOptions.asMap().hasKey(cp::Rpc::KEY_BROKER); } -void ServerConnection::sendMessage(const chainpack::RpcMessage &rpc_msg) -{ - sendRpcValue(rpc_msg.value()); -} - -void ServerConnection::onRpcDataReceived(shv::chainpack::Rpc::ProtocolType protocol_type, shv::chainpack::RpcValue::MetaData &&md, std::string &&msg_data) +void ServerConnection::onRpcFrameReceived(chainpack::RpcFrame &&frame) { if(isLoginPhase()) { - shv::chainpack::RpcValue rpc_val = decodeData(protocol_type, msg_data, 0); - rpc_val.setMetaData(std::move(md)); - cp::RpcMessage msg(rpc_val); + auto msg = frame.toRpcMessage(); processLoginPhase(msg); return; } - Super::onRpcDataReceived(protocol_type, std::move(md), std::move(msg_data)); + Super::onRpcFrameReceived(std::move(frame)); } void ServerConnection::onRpcMessageReceived(const chainpack::RpcMessage &msg) diff --git a/libshviotqt/src/rpc/socketrpcconnection.cpp b/libshviotqt/src/rpc/socketrpcconnection.cpp index dd8ccc621..1c85219e3 100644 --- a/libshviotqt/src/rpc/socketrpcconnection.cpp +++ b/libshviotqt/src/rpc/socketrpcconnection.cpp @@ -70,7 +70,7 @@ void SocketRpcConnection::setSocket(Socket *socket) shvDebug() << this << "Socket disconnected!!!"; emit socketConnectedChanged(false); }); - connect(socket, &Socket::socketReset, this, &SocketRpcConnection::clearSendBuffers); + //connect(socket, &Socket::socketReset, this, &SocketRpcConnection::clearSendBuffers); } bool SocketRpcConnection::hasSocket() const @@ -78,11 +78,6 @@ bool SocketRpcConnection::hasSocket() const return m_socket != nullptr; } -void SocketRpcConnection::setProtocolTypeAsInt(int v) -{ - shv::chainpack::RpcDriver::setProtocolType(static_cast(v)); -} - Socket *SocketRpcConnection::socket() { if(!m_socket) @@ -115,13 +110,12 @@ void SocketRpcConnection::onReadyRead() f->flush(); } #endif - onBytesRead(ba.toStdString()); + onFrameDataRead(ba.toStdString()); } void SocketRpcConnection::onBytesWritten() { logRpcData() << "onBytesWritten()"; - enqueueDataToSend(MessageData()); } void SocketRpcConnection::onParseDataException(const chainpack::ParseException &e) @@ -135,31 +129,14 @@ bool SocketRpcConnection::isOpen() return isSocketConnected(); } -int64_t SocketRpcConnection::writeBytes(const char *bytes, size_t length) -{ - return socket()->write(bytes, static_cast(length)); -} - -void SocketRpcConnection::writeMessageBegin() -{ - if(m_socket) - m_socket->writeMessageBegin(); -} - -void SocketRpcConnection::writeMessageEnd() -{ - if(m_socket) - m_socket->writeMessageEnd(); -} - -Q_SLOT void SocketRpcConnection::sendRpcValue(const shv::chainpack::RpcValue &rpc_val) +int64_t SocketRpcConnection::writeFrameData(std::string &&frame_data) { - shv::chainpack::RpcDriver::sendRpcValue(rpc_val); + return socket()->write(frame_data.data(), frame_data.size()); } -void SocketRpcConnection::clearSendBuffers() +void SocketRpcConnection::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) { - shv::chainpack::RpcDriver::clearSendBuffers(); + shv::chainpack::RpcDriver::sendRpcMessage(rpc_msg); } void SocketRpcConnection::closeSocket() diff --git a/libshviotqt/tests/serialportsocket/mockrpcconnection.cpp b/libshviotqt/tests/serialportsocket/mockrpcconnection.cpp index 8a965bf6d..d94991ee9 100644 --- a/libshviotqt/tests/serialportsocket/mockrpcconnection.cpp +++ b/libshviotqt/tests/serialportsocket/mockrpcconnection.cpp @@ -5,7 +5,6 @@ MockRpcConnection::MockRpcConnection(QObject *parent) : shv::iotqt::rpc::SocketRpcConnection{parent} { - setProtocolType(shv::chainpack::Rpc::ProtocolType::ChainPack); } void MockRpcConnection::close() @@ -20,7 +19,7 @@ void MockRpcConnection::abort() void MockRpcConnection::sendMessage(const shv::chainpack::RpcMessage &rpc_msg) { - sendRpcValue(rpc_msg.value()); + sendMessage(rpc_msg.value()); } void MockRpcConnection::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) From 759688360cceadf775fcc86a39116530d5c58716 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 27 Jan 2024 14:17:38 +0100 Subject: [PATCH 02/17] sendMessage() in all interfaces renamed to sendRpcMessage() for consistency --- libshvbroker/src/brokerapp.cpp | 18 +++++++++--------- libshvbroker/src/clientshvnode.cpp | 2 +- .../src/rpc/clientconnectiononbroker.cpp | 4 ++-- .../src/rpc/clientconnectiononbroker.h | 4 ++-- libshvbroker/src/rpc/commonrpcclienthandle.h | 4 ++-- .../src/rpc/masterbrokerconnection.cpp | 6 +++--- libshvbroker/src/rpc/masterbrokerconnection.h | 4 ++-- .../include/shv/chainpack/irpcconnection.h | 2 +- .../src/chainpack/irpcconnection.cpp | 10 +++++----- libshviotqt/CMakeLists.txt | 2 +- .../include/shv/iotqt/rpc/clientconnection.h | 2 +- libshviotqt/src/rpc/clientconnection.cpp | 2 +- libshviotqt/src/rpc/serverconnection.cpp | 2 +- .../serialportsocket/mockrpcconnection.cpp | 5 ----- .../tests/serialportsocket/mockrpcconnection.h | 1 - .../tests/serialportsocket/mockserialport.cpp | 2 +- .../serialportsocket/test_serialportsocket.cpp | 4 ++-- 17 files changed, 34 insertions(+), 40 deletions(-) diff --git a/libshvbroker/src/brokerapp.cpp b/libshvbroker/src/brokerapp.cpp index 7fe58257d..7e08e62ad 100644 --- a/libshvbroker/src/brokerapp.cpp +++ b/libshvbroker/src/brokerapp.cpp @@ -1159,7 +1159,7 @@ void BrokerApp::onRpcFrameReceived(int connection_id, shv::chainpack::RpcFrame & logServiceProvidersM() << "forwarded shv path:" << resolved_local_path; cp::RpcRequest::setShvPath(frame.meta, resolved_local_path); cp::RpcMessage::pushCallerId(frame.meta, connection_id); - master_broker->sendFrame(std::move(frame)); + master_broker->sendRpcFrame(std::move(frame)); return; } } @@ -1247,7 +1247,7 @@ void BrokerApp::onRpcFrameReceived(int connection_id, shv::chainpack::RpcFrame & rsp.setError(cp::RpcResponse::Error::create( cp::RpcResponse::Error::MethodCallException , e.what())); - connection_handle->sendMessage(rsp); + connection_handle->sendRpcMessage(rsp); } } } @@ -1285,7 +1285,7 @@ void BrokerApp::onRpcFrameReceived(int connection_id, shv::chainpack::RpcFrame & rpc::CommonRpcClientHandle *cch = commonClientConnectionById(connection_id); if(cch) { logTunnelD() << "Sending FindTunnelResponse:" << msg.toPrettyString(); - cch->sendMessage(msg); + cch->sendRpcMessage(msg); } return; } @@ -1294,7 +1294,7 @@ void BrokerApp::onRpcFrameReceived(int connection_id, shv::chainpack::RpcFrame & } rpc::CommonRpcClientHandle *cch = commonClientConnectionById(caller_id); if(cch) { - cch->sendFrame(std::move(frame)); + cch->sendRpcFrame(std::move(frame)); } else { shvWarning() << "Got RPC response for not-exists connection, may be it was closed meanwhile. Connection id:" << caller_id; @@ -1332,7 +1332,7 @@ void BrokerApp::onRpcFrameReceived(int connection_id, shv::chainpack::RpcFrame & { cp::Rpc::PAR_PATH, sig_shv_path}, { cp::Rpc::PAR_METHOD, cp::RpcMessage::method(frame.meta).toString()}}) .setShvPath(cp::Rpc::DIR_BROKER_APP); - client_connection->sendMessage(rq); + client_connection->sendRpcMessage(rq); } } } @@ -1352,7 +1352,7 @@ void BrokerApp::onRootNodeSendRpcMesage(const shv::chainpack::RpcMessage &msg) shv::chainpack::RpcValue::Int connection_id = resp.popCallerId(); rpc::CommonRpcClientHandle *conn = commonClientConnectionById(connection_id); if(conn) - conn->sendMessage(resp); + conn->sendRpcMessage(resp); else shvError() << "Cannot find connection for ID:" << connection_id; return; @@ -1405,12 +1405,12 @@ bool BrokerApp::sendNotifyToSubscribers(const chainpack::RpcFrame &frame) const rpc::ClientConnectionOnBroker::Subscription &subs = conn->subscriptionAt(static_cast(subs_ix)); std::string new_path = conn->toSubscribedPath(subs, shv_path.asString()); if(new_path == shv_path.asString()) { - conn->sendFrame(chainpack::RpcFrame(frame)); + conn->sendRpcFrame(chainpack::RpcFrame(frame)); } else { auto frame2 = frame; cp::RpcMessage::setShvPath(frame2.meta, new_path); - conn->sendFrame(std::move(frame2)); + conn->sendRpcFrame(std::move(frame2)); } subs_sent = true; } @@ -1434,7 +1434,7 @@ void BrokerApp::sendNotifyToSubscribers(const std::string &shv_path, const std:: std::string new_path = conn->toSubscribedPath(subs, shv_path); if(new_path != shv_path) sig.setShvPath(new_path); - conn->sendMessage(sig); + conn->sendRpcMessage(sig); } } } diff --git a/libshvbroker/src/clientshvnode.cpp b/libshvbroker/src/clientshvnode.cpp index e3bd9c52e..466e89f48 100644 --- a/libshvbroker/src/clientshvnode.cpp +++ b/libshvbroker/src/clientshvnode.cpp @@ -49,7 +49,7 @@ void ClientShvNode::handleRpcFrame(chainpack::RpcFrame &&frame) { rpc::ClientConnectionOnBroker *conn = connection(); if(conn) - conn->sendFrame(std::move(frame)); + conn->sendRpcFrame(std::move(frame)); } shv::chainpack::RpcValue ClientShvNode::hasChildren(const StringViewList &shv_path) diff --git a/libshvbroker/src/rpc/clientconnectiononbroker.cpp b/libshvbroker/src/rpc/clientconnectiononbroker.cpp index 25a71b265..20c304e45 100644 --- a/libshvbroker/src/rpc/clientconnectiononbroker.cpp +++ b/libshvbroker/src/rpc/clientconnectiononbroker.cpp @@ -163,7 +163,7 @@ void ClientConnectionOnBroker::setIdleWatchDogTimeOut(int sec) m_idleWatchDogTimer->start(sec * 1000); } -void ClientConnectionOnBroker::sendMessage(const shv::chainpack::RpcMessage &rpc_msg) +void ClientConnectionOnBroker::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) { logRpcMsg() << SND_LOG_ARROW << "client id:" << connectionId() @@ -171,7 +171,7 @@ void ClientConnectionOnBroker::sendMessage(const shv::chainpack::RpcMessage &rpc chainpack::RpcDriver::sendRpcMessage(rpc_msg); } -void ClientConnectionOnBroker::sendFrame(chainpack::RpcFrame &&frame) +void ClientConnectionOnBroker::sendRpcFrame(chainpack::RpcFrame &&frame) { logRpcMsg() << SND_LOG_ARROW << "client id:" << connectionId() diff --git a/libshvbroker/src/rpc/clientconnectiononbroker.h b/libshvbroker/src/rpc/clientconnectiononbroker.h index 4698d2fd8..50dc78b26 100644 --- a/libshvbroker/src/rpc/clientconnectiononbroker.h +++ b/libshvbroker/src/rpc/clientconnectiononbroker.h @@ -46,8 +46,8 @@ class ClientConnectionOnBroker : public shv::iotqt::rpc::ServerConnection, publi void setIdleWatchDogTimeOut(int sec); - void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) override; - void sendFrame(shv::chainpack::RpcFrame &&frame) override; + void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) override; + void sendRpcFrame(shv::chainpack::RpcFrame &&frame) override; Subscription createSubscription(const std::string &shv_path, const std::string &method) override; std::string toSubscribedPath(const Subscription &subs, const std::string &signal_path) const override; diff --git a/libshvbroker/src/rpc/commonrpcclienthandle.h b/libshvbroker/src/rpc/commonrpcclienthandle.h index 39d5cf8eb..34dea1bfb 100644 --- a/libshvbroker/src/rpc/commonrpcclienthandle.h +++ b/libshvbroker/src/rpc/commonrpcclienthandle.h @@ -42,8 +42,8 @@ class CommonRpcClientHandle virtual bool isSlaveBrokerConnection() const = 0; virtual bool isMasterBrokerConnection() const = 0; - virtual void sendFrame(chainpack::RpcFrame &&frame) = 0; - virtual void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) = 0; + virtual void sendRpcFrame(chainpack::RpcFrame &&frame) = 0; + virtual void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) = 0; protected: std::vector m_subscriptions; }; diff --git a/libshvbroker/src/rpc/masterbrokerconnection.cpp b/libshvbroker/src/rpc/masterbrokerconnection.cpp index b3bfecf43..74a2a89c3 100644 --- a/libshvbroker/src/rpc/masterbrokerconnection.cpp +++ b/libshvbroker/src/rpc/masterbrokerconnection.cpp @@ -85,7 +85,7 @@ bool MasterBrokerConnection::isMasterBrokerConnection() const return true; } -void MasterBrokerConnection::sendFrame(chainpack::RpcFrame &&frame) +void MasterBrokerConnection::sendRpcFrame(chainpack::RpcFrame &&frame) { logRpcMsg() << SND_LOG_ARROW << "client id:" << connectionId() @@ -93,9 +93,9 @@ void MasterBrokerConnection::sendFrame(chainpack::RpcFrame &&frame) Super::sendRpcFrame(std::move(frame)); } -void MasterBrokerConnection::sendMessage(const shv::chainpack::RpcMessage &rpc_msg) +void MasterBrokerConnection::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) { - Super::sendMessage(rpc_msg); + Super::sendRpcMessage(rpc_msg); } CommonRpcClientHandle::Subscription MasterBrokerConnection::createSubscription(const std::string &shv_path, const std::string &method) diff --git a/libshvbroker/src/rpc/masterbrokerconnection.h b/libshvbroker/src/rpc/masterbrokerconnection.h index 151eed5db..54a23458a 100644 --- a/libshvbroker/src/rpc/masterbrokerconnection.h +++ b/libshvbroker/src/rpc/masterbrokerconnection.h @@ -26,8 +26,8 @@ class MasterBrokerConnection : public shv::iotqt::rpc::DeviceConnection, public bool isSlaveBrokerConnection() const override; bool isMasterBrokerConnection() const override; - void sendFrame(shv::chainpack::RpcFrame &&frame) override; - void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) override; + void sendRpcFrame(shv::chainpack::RpcFrame &&frame) override; + void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) override; Subscription createSubscription(const std::string &shv_path, const std::string &method) override; std::string toSubscribedPath(const Subscription &subs, const std::string &signal_path) const override; diff --git a/libshvchainpack/include/shv/chainpack/irpcconnection.h b/libshvchainpack/include/shv/chainpack/irpcconnection.h index af6dc22f9..3cefbb4bc 100644 --- a/libshvchainpack/include/shv/chainpack/irpcconnection.h +++ b/libshvchainpack/include/shv/chainpack/irpcconnection.h @@ -26,7 +26,7 @@ class SHVCHAINPACK_DECL_EXPORT IRpcConnection virtual void close() = 0; virtual void abort() = 0; - virtual void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) = 0; + virtual void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) = 0; virtual void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) = 0; int nextRequestId(); diff --git a/libshvchainpack/src/chainpack/irpcconnection.cpp b/libshvchainpack/src/chainpack/irpcconnection.cpp index f945c91f1..13bab6adc 100644 --- a/libshvchainpack/src/chainpack/irpcconnection.cpp +++ b/libshvchainpack/src/chainpack/irpcconnection.cpp @@ -25,7 +25,7 @@ void IRpcConnection::sendShvSignal(const std::string &shv_path, std::string meth rq.setShvPath(shv_path); rq.setMethod(std::move(method)); rq.setParams(params); - sendMessage(rq); + sendRpcMessage(rq); } [[deprecated("Use sendSignal instead")]] void IRpcConnection::sendNotify(std::string method, const shv::chainpack::RpcValue ¶ms) @@ -43,7 +43,7 @@ void IRpcConnection::sendResponse(const RpcValue &request_id, const RpcValue &re RpcResponse resp; resp.setRequestId(request_id); resp.setResult(result); - sendMessage(resp); + sendRpcMessage(resp); } void IRpcConnection::sendError(const RpcValue &request_id, const RpcResponse::Error &error) @@ -51,7 +51,7 @@ void IRpcConnection::sendError(const RpcValue &request_id, const RpcResponse::Er RpcResponse resp; resp.setRequestId(request_id); resp.setError(error); - sendMessage(resp); + sendRpcMessage(resp); } int IRpcConnection::nextRequestId() @@ -79,7 +79,7 @@ int IRpcConnection::callMethod(const RpcRequest &rq) id = nextRequestId(); _rq.setRequestId(id); } - sendMessage(rq); + sendRpcMessage(rq); return id; } @@ -110,7 +110,7 @@ int IRpcConnection::callShvMethod(int rq_id, const std::string &shv_path, std::s rq.setUserId(user_id); if(!shv_path.empty()) rq.setShvPath(shv_path); - sendMessage(rq); + sendRpcMessage(rq); return rq_id; } diff --git a/libshviotqt/CMakeLists.txt b/libshviotqt/CMakeLists.txt index 204825ef9..97d6dac77 100644 --- a/libshviotqt/CMakeLists.txt +++ b/libshviotqt/CMakeLists.txt @@ -83,7 +83,7 @@ endfunction(add_shviotqt_serialportsocket_test) if(BUILD_TESTING) add_shviotqt_serialportsocket_test(serialportsocket) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_serialportsocket") - set_property(TEST test_iotqt_serialportsocket APPEND PROPERTY ENVIRONMENT "TESTS_DIR=${CMAKE_CURRENT_BINARY_DIR}/test_serialportsocket") + target_compile_definitions(test_iotqt_serialportsocket PRIVATE TESTS_DIR="${CMAKE_CURRENT_BINARY_DIR}/test_serialportsocket") endif() install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/shv" TYPE INCLUDE) diff --git a/libshviotqt/include/shv/iotqt/rpc/clientconnection.h b/libshviotqt/include/shv/iotqt/rpc/clientconnection.h index b3cf08809..86d392b4f 100644 --- a/libshviotqt/include/shv/iotqt/rpc/clientconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/clientconnection.h @@ -74,7 +74,7 @@ class SHVIOTQT_DECL_EXPORT ClientConnection : public SocketRpcConnection bool isShvPathMutedInLog(const std::string &shv_path, const std::string &method) const; public: /// IRpcConnection interface implementation - void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) override; + void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) override; void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) override; static QUrl connectionUrlFromString(const QString &url_str); protected: diff --git a/libshviotqt/src/rpc/clientconnection.cpp b/libshviotqt/src/rpc/clientconnection.cpp index 4251737b0..083ec1285 100644 --- a/libshviotqt/src/rpc/clientconnection.cpp +++ b/libshviotqt/src/rpc/clientconnection.cpp @@ -272,7 +272,7 @@ bool ClientConnection::isBrokerConnected() const static constexpr std::string_view::size_type MAX_LOG_LEN = 1024; static const auto TOPIC_RPC_MSG = "RpcMsg"; -void ClientConnection::sendMessage(const cp::RpcMessage &rpc_msg) +void ClientConnection::sendRpcMessage(const cp::RpcMessage &rpc_msg) { if(NecroLog::shouldLog(NecroLog::Level::Message, NecroLog::LogContext(__FILE__, __LINE__, TOPIC_RPC_MSG))) { if(isShvPathMutedInLog(rpc_msg.shvPath().asString(), rpc_msg.method().asString())) { diff --git a/libshviotqt/src/rpc/serverconnection.cpp b/libshviotqt/src/rpc/serverconnection.cpp index 703c9bf51..b1a401396 100644 --- a/libshviotqt/src/rpc/serverconnection.cpp +++ b/libshviotqt/src/rpc/serverconnection.cpp @@ -171,7 +171,7 @@ void ServerConnection::setLoginResult(const chainpack::UserLoginResult &result) + " reason: " + result.loginError + " at: " + connectionName())); } - sendMessage(resp); + sendRpcMessage(resp); } } diff --git a/libshviotqt/tests/serialportsocket/mockrpcconnection.cpp b/libshviotqt/tests/serialportsocket/mockrpcconnection.cpp index d94991ee9..40c137e4c 100644 --- a/libshviotqt/tests/serialportsocket/mockrpcconnection.cpp +++ b/libshviotqt/tests/serialportsocket/mockrpcconnection.cpp @@ -17,11 +17,6 @@ void MockRpcConnection::abort() socket()->abort(); } -void MockRpcConnection::sendMessage(const shv::chainpack::RpcMessage &rpc_msg) -{ - sendMessage(rpc_msg.value()); -} - void MockRpcConnection::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) { emit rpcMessageReceived(msg); diff --git a/libshviotqt/tests/serialportsocket/mockrpcconnection.h b/libshviotqt/tests/serialportsocket/mockrpcconnection.h index 461d375e8..12f16c501 100644 --- a/libshviotqt/tests/serialportsocket/mockrpcconnection.h +++ b/libshviotqt/tests/serialportsocket/mockrpcconnection.h @@ -10,7 +10,6 @@ class MockRpcConnection : public shv::iotqt::rpc::SocketRpcConnection void close() override; void abort() override; - void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) override; void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) override; Q_SIGNAL void rpcMessageReceived(const shv::chainpack::RpcMessage &msg); diff --git a/libshviotqt/tests/serialportsocket/mockserialport.cpp b/libshviotqt/tests/serialportsocket/mockserialport.cpp index d83896c3d..dd984ae28 100644 --- a/libshviotqt/tests/serialportsocket/mockserialport.cpp +++ b/libshviotqt/tests/serialportsocket/mockserialport.cpp @@ -18,7 +18,7 @@ bool MockSerialPort::open(OpenMode mode) Q_UNUSED(mode); close(); { - const auto tests_dir = getenv("TESTS_DIR"); + const auto tests_dir = TESTS_DIR; if (!tests_dir) { throw std::runtime_error("TESTS_DIR not set"); } diff --git a/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp b/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp index a8c271c08..15a52fadb 100644 --- a/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp +++ b/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp @@ -59,7 +59,7 @@ DOCTEST_TEST_CASE("Send") rq.setParams(p); serial->clearWrittenData(); rec_msg = {}; - conn.sendMessage(rq); + conn.sendRpcMessage(rq); auto data = serial->writtenData(); vector rubbish1 = { @@ -103,7 +103,7 @@ DOCTEST_TEST_CASE("Test CRC error") rq.setParams(123); serial->clearWrittenData(); - conn.sendMessage(rq); + conn.sendRpcMessage(rq); auto data = serial->writtenData(); data[5] = ~data[5]; From 79d55b12f345114c985596a2c9cb4efe34e70da2 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 28 Jan 2024 11:03:23 +0100 Subject: [PATCH 03/17] readFrameData() and readFrameData() implemented in all Socket descendants --- .../include/shv/chainpack/rpcdriver.h | 6 +- .../include/shv/chainpack/socketrpcdriver.h | 2 +- libshvchainpack/src/chainpack/rpcdriver.cpp | 34 +- libshvchainpack/src/chainpack/rpcmessage.cpp | 4 + .../src/chainpack/socketrpcdriver.cpp | 8 +- libshviotqt/CMakeLists.txt | 2 + .../include/shv/iotqt/rpc/localsocket.h | 44 ++ .../include/shv/iotqt/rpc/serialportsocket.h | 78 ++- libshviotqt/include/shv/iotqt/rpc/socket.h | 106 ++-- .../shv/iotqt/rpc/socketrpcconnection.h | 3 +- libshviotqt/include/shv/iotqt/rpc/websocket.h | 13 +- libshviotqt/src/rpc/clientconnection.cpp | 9 +- libshviotqt/src/rpc/localsocket.cpp | 176 +++++++ libshviotqt/src/rpc/serialportsocket.cpp | 456 +++++++----------- libshviotqt/src/rpc/socket.cpp | 219 ++++----- libshviotqt/src/rpc/socketrpcconnection.cpp | 16 +- libshviotqt/src/rpc/websocket.cpp | 58 +-- .../test_serialportsocket.cpp | 9 +- 18 files changed, 664 insertions(+), 579 deletions(-) create mode 100644 libshviotqt/include/shv/iotqt/rpc/localsocket.h create mode 100644 libshviotqt/src/rpc/localsocket.cpp diff --git a/libshvchainpack/include/shv/chainpack/rpcdriver.h b/libshvchainpack/include/shv/chainpack/rpcdriver.h index ce0d79828..5e3b7f19d 100644 --- a/libshvchainpack/include/shv/chainpack/rpcdriver.h +++ b/libshvchainpack/include/shv/chainpack/rpcdriver.h @@ -30,17 +30,13 @@ class SHVCHAINPACK_DECL_EXPORT RpcDriver protected: virtual bool isOpen() = 0; - /// write fame data to socket - /// @return number of writen bytes - virtual int64_t writeFrameData(std::string &&frame_data) = 0; + virtual void writeFrameData(std::string &&frame_data) = 0; /// call it when new data arrived virtual void onFrameDataRead(std::string &&frame_data); virtual void onRpcFrameReceived(RpcFrame &&frame); virtual void onParseDataException(const shv::chainpack::ParseException &e) = 0; virtual void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) = 0; -private: - void processReadFrameData(std::string &&frame_data); private: static int s_defaultRpcTimeoutMsec; }; diff --git a/libshvchainpack/include/shv/chainpack/socketrpcdriver.h b/libshvchainpack/include/shv/chainpack/socketrpcdriver.h index e7216ad28..86fbd2881 100644 --- a/libshvchainpack/include/shv/chainpack/socketrpcdriver.h +++ b/libshvchainpack/include/shv/chainpack/socketrpcdriver.h @@ -21,7 +21,7 @@ class SHVCHAINPACK_DECL_EXPORT SocketRpcDriver : public RpcDriver void sendNotify(std::string &&method, const RpcValue &result); protected: bool isOpen() override; - int64_t writeFrameData(std::string &&frame_data) override; + void writeFrameData(std::string &&frame_data) override; virtual void idleTaskOnSelectTimeout(); private: diff --git a/libshvchainpack/src/chainpack/rpcdriver.cpp b/libshvchainpack/src/chainpack/rpcdriver.cpp index 66791d3e5..536ac7ceb 100644 --- a/libshvchainpack/src/chainpack/rpcdriver.cpp +++ b/libshvchainpack/src/chainpack/rpcdriver.cpp @@ -51,42 +51,34 @@ void RpcDriver::sendRpcFrame(RpcFrame &&frame) } void RpcDriver::onFrameDataRead(std::string &&frame_data) -{ - logRpcData().nospace() << __FUNCTION__ << " " << frame_data.length() << " bytes of data read:\n" << shv::chainpack::Utils::hexDump(frame_data); - processReadFrameData(std::move(frame_data)); -} - -int RpcDriver::defaultRpcTimeoutMsec() -{ - return s_defaultRpcTimeoutMsec; -} - -void RpcDriver::setDefaultRpcTimeoutMsec(int msec) -{ - s_defaultRpcTimeoutMsec = msec; -} - -void RpcDriver::processReadFrameData(std::string &&frame_data) { logRpcData() << __PRETTY_FUNCTION__ << "+++++++++++++++++++++++++++++++++"; - using namespace shv::chainpack; - - logRpcData().nospace() << "READ DATA " << frame_data.size() << " bytes of data read:\n" << shv::chainpack::Utils::hexDump(frame_data); + logRpcData().nospace() << "FRAME DATA " << frame_data.size() << " bytes of data read:\n" << shv::chainpack::Utils::hexDump(frame_data); try { auto frame = RpcFrame::fromChainPack(std::move(frame_data)); onRpcFrameReceived(std::move(frame)); } catch (const ParseException &e) { - logRpcDataW() << "ERROR - RpcMessage header corrupted:" << e.msg(); + logRpcDataW() << "ERROR - Rpc frame data corrupted:" << e.msg(); //logRpcDataW() << "The error occured in data:\n" << shv::chainpack::utils::hexDump(m_readData.data(), 1024); onParseDataException(e); return; } catch (const std::exception &e) { - nError() << "processReadFrameData exception:" << e.what(); + nError() << "ERROR - Rpc frame process error:" << e.what(); } } +int RpcDriver::defaultRpcTimeoutMsec() +{ + return s_defaultRpcTimeoutMsec; +} + +void RpcDriver::setDefaultRpcTimeoutMsec(int msec) +{ + s_defaultRpcTimeoutMsec = msec; +} + void RpcDriver::onRpcFrameReceived(RpcFrame &&frame) { auto msg = frame.toRpcMessage(); diff --git a/libshvchainpack/src/chainpack/rpcmessage.cpp b/libshvchainpack/src/chainpack/rpcmessage.cpp index 75b63c5f0..ca133375a 100644 --- a/libshvchainpack/src/chainpack/rpcmessage.cpp +++ b/libshvchainpack/src/chainpack/rpcmessage.cpp @@ -73,6 +73,10 @@ std::string RpcFrame::toChainPack() const RpcFrame RpcFrame::fromChainPack(std::string &&frame_data) { std::istringstream in(frame_data); + auto protocol = in.get(); + if (protocol != static_cast(Rpc::ProtocolType::ChainPack)) { + throw std::runtime_error("Invalid protocol type"); + } ChainPackReader rd(in); RpcValue::MetaData meta; rd.read(meta); diff --git a/libshvchainpack/src/chainpack/socketrpcdriver.cpp b/libshvchainpack/src/chainpack/socketrpcdriver.cpp index a2075f4c5..a40e9a6ad 100644 --- a/libshvchainpack/src/chainpack/socketrpcdriver.cpp +++ b/libshvchainpack/src/chainpack/socketrpcdriver.cpp @@ -53,20 +53,16 @@ void SocketRpcDriver::idleTaskOnSelectTimeout() { } -int64_t SocketRpcDriver::writeFrameData(std::string &&frame_data) +void SocketRpcDriver::writeFrameData(std::string &&frame_data) { if(!isOpen()) { nInfo() << "Write to closed socket"; - return 0; + return; } - flush(); if (m_writeBuffer.size() + frame_data.size() < m_maxWriteBufferLength) { - auto sz = frame_data.size(); m_writeBuffer += std::move(frame_data); flush(); - return sz; } - return -1; } bool SocketRpcDriver::flush() diff --git a/libshviotqt/CMakeLists.txt b/libshviotqt/CMakeLists.txt index 97d6dac77..61cb8f8c5 100644 --- a/libshviotqt/CMakeLists.txt +++ b/libshviotqt/CMakeLists.txt @@ -15,6 +15,7 @@ qt_add_library(libshviotqt src/rpc/rpcresponsecallback.cpp src/rpc/serverconnection.cpp src/rpc/socket.cpp + src/rpc/localsocket.cpp src/rpc/socketrpcconnection.cpp src/rpc/tcpserver.cpp src/utils.cpp @@ -34,6 +35,7 @@ qt_add_library(libshviotqt include/shv/iotqt/rpc/tcpserver.h include/shv/iotqt/rpc/rpcresponsecallback.h include/shv/iotqt/rpc/socket.h + include/shv/iotqt/rpc/localsocket.h include/shv/iotqt/rpc/clientconnection.h include/shv/iotqt/rpc/serverconnection.h include/shv/iotqt/rpc/serialportsocket.h diff --git a/libshviotqt/include/shv/iotqt/rpc/localsocket.h b/libshviotqt/include/shv/iotqt/rpc/localsocket.h new file mode 100644 index 000000000..002976c75 --- /dev/null +++ b/libshviotqt/include/shv/iotqt/rpc/localsocket.h @@ -0,0 +1,44 @@ +#ifndef SHV_IOTQT_RPC_LOCALSOCKET_H +#define SHV_IOTQT_RPC_LOCALSOCKET_H + +#include "socket.h" + +namespace shv { +namespace iotqt { +namespace rpc { + +class SHVIOTQT_DECL_EXPORT LocalSocket : public Socket +{ + Q_OBJECT + + using Super = Socket; +public: + enum class Protocol {Stream, Serial}; + LocalSocket(QLocalSocket *socket, Protocol protocol, QObject *parent = nullptr); + ~LocalSocket() override; + + std::string readFrameData() override; + void writeFrameData(std::string &&frame_data) override; + + void connectToHost(const QUrl &url) override; + void close() override; + void abort() override; + QAbstractSocket::SocketState state() const override; + QString errorString() const override; + QHostAddress peerAddress() const override; + quint16 peerPort() const override; + void ignoreSslErrors() override; +protected: + void onDataReadyRead(); + void flushWriteBuffer(); +protected: + QLocalSocket *m_socket = nullptr; + FrameReader *m_frameReader; + FrameWriter *m_frameWriter; +}; + +} // namespace rpc +} // namespace iotqt +} // namespace shv + +#endif // SHV_IOTQT_RPC_LOCALSOCKET_H diff --git a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h index 0dd0ab41b..856f86346 100644 --- a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h @@ -6,30 +6,51 @@ #include #include -#include - class QSerialPort; class QTimer; namespace shv::iotqt::rpc { +class SerialFrameReader : public FrameReader { +public: + ~SerialFrameReader() override = default; + + void addData(std::string_view data) override; +private: + enum class ReadState {WaitingForStx, WaitingForEtx, WaitingForCrc}; +private: + bool inEscape() const; + void setState(ReadState state); + void finishFrame(); +private: + ReadState m_readState = ReadState::WaitingForStx; + uint8_t m_recentByte = 0; + std::string m_readBuffer; + std::string m_crcBuffer; + shv::chainpack::Crc32Posix m_crcDigest; + bool m_withCrcCheck = true; +}; + +class SerialFrameWriter : public FrameWriter { +public: + ~SerialFrameWriter() override = default; + + void addFrame(std::string &&frame_data) override; +public: + bool m_withCrcCheck = true; +}; + class SHVIOTQT_DECL_EXPORT SerialPortSocket : public Socket { Q_OBJECT using Super = Socket; -public: - enum class ReadMessageError {Ok = 0, ErrorUnexpectedStx, ErrorUnexpectedEtx, ErrorEscape, ErrorCrc, ErrorTimeout}; - enum EscCodes { - STX = 0xA2, - ETX = 0xA3, - ESTX = 0xA4, - EETX = 0xA5, - ESC = 0xAA, - }; public: SerialPortSocket(QSerialPort *port, QObject *parent = nullptr); + std::string readFrameData() override; + void writeFrameData(std::string &&frame_data) override; + void setReceiveTimeout(int millis); void connectToHost(const QUrl &url) override; @@ -38,50 +59,23 @@ class SHVIOTQT_DECL_EXPORT SerialPortSocket : public Socket void reset(); QAbstractSocket::SocketState state() const override; QString errorString() const override; - QString readMessageErrorString() const; - ReadMessageError readMessageError() const; QHostAddress peerAddress() const override; quint16 peerPort() const override; - QByteArray readAll() override; - qint64 write(const char *data, qint64 max_size) override; - void writeMessageBegin() override; - void writeMessageEnd() override; void ignoreSslErrors() override; protected: void restartReceiveTimeoutTimer(); private: - - class UnescapeBuffer - { - public: - ReadMessageError append(uint8_t b); - void clear(); - - QByteArray data; - bool inEscape = false; - }; - - enum class ReadMessageState {WaitingForStx, WaitingForEtx, WaitingForCrc}; - void setState(QAbstractSocket::SocketState state); - void onSerialDataReadyRead(); + void onDataReadyRead(); + void flushWriteBuffer(); void onParseDataException(const shv::chainpack::ParseException &e) override; - void setReadMessageState(ReadMessageState st); - void setReadMessageError(ReadMessageError err); qint64 writeBytesEscaped(const char *data, qint64 max_size); private: QSerialPort *m_port = nullptr; QAbstractSocket::SocketState m_state = QAbstractSocket::UnconnectedState; - ReadMessageState m_readMessageState = ReadMessageState::WaitingForStx; - ReadMessageError m_readMessageError = ReadMessageError::Ok; QTimer *m_readDataTimeout = nullptr; - shv::chainpack::Crc32Posix m_readMessageCrc; - UnescapeBuffer m_readMessageBuffer; - UnescapeBuffer m_readMessageCrcBuffer; - QQueue m_receivedMessages; - - bool m_escWritten = false; - shv::chainpack::Crc32Posix m_writeMessageCrc; + SerialFrameReader m_frameReader; + SerialFrameWriter m_frameWriter; }; } diff --git a/libshviotqt/include/shv/iotqt/rpc/socket.h b/libshviotqt/include/shv/iotqt/rpc/socket.h index b98ddf46f..960b27f19 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socket.h +++ b/libshviotqt/include/shv/iotqt/rpc/socket.h @@ -7,6 +7,8 @@ #include #include +#include + class QTcpSocket; class QLocalSocket; class QSerialPort; @@ -17,13 +19,63 @@ namespace shv { namespace iotqt { namespace rpc { +class FrameReader { +public: + virtual ~FrameReader() = default; + virtual void addData(std::string_view data) = 0; + bool isEmpty() const { return m_frames.empty(); } + std::string getFrame() { + if (!m_frames.empty()) { + auto frame = m_frames.front(); + m_frames.pop_front(); + return frame; + } + return {}; + } +protected: + std::deque m_frames; +}; + +class FrameWriter { +public: + virtual ~FrameWriter() = default; + virtual void addFrame(std::string &&frame_data) = 0; + QByteArray getMessageDataToWrite() { + if (!m_messagesToWrite.empty()) { + return m_messagesToWrite.takeFirst(); + } + return {}; + } + void pushUnwrittenMessageData(QByteArray data) { + m_messagesToWrite.insert(0, data); + } +protected: + QList m_messagesToWrite; +}; + +class StreamFrameReader : public FrameReader { +public: + ~StreamFrameReader() override = default; + + void addData(std::string_view data) override; +private: + std::string m_readBuffer; +}; + +class StreamFrameWriter : public FrameWriter { +public: + ~StreamFrameWriter() override = default; + + void addFrame(std::string &&frame_data) override; +}; + /// wrapper class for QTcpSocket and QWebSocket class SHVIOTQT_DECL_EXPORT Socket : public QObject { Q_OBJECT public: - enum class Scheme { Tcp = 0, Ssl, WebSocket, WebSocketSecure, SerialPort, LocalSocket }; + enum class Scheme { Tcp = 0, Ssl, WebSocket, WebSocketSecure, SerialPort, LocalSocket, LocalSocketSerial }; public: explicit Socket(QObject *parent = nullptr); @@ -38,13 +90,12 @@ class SHVIOTQT_DECL_EXPORT Socket : public QObject virtual QAbstractSocket::SocketState state() const = 0; virtual QString errorString() const = 0; - virtual QHostAddress peerAddress() const = 0; - virtual quint16 peerPort() const = 0; + virtual QHostAddress peerAddress() const = 0; + virtual quint16 peerPort() const = 0; + + virtual std::string readFrameData() = 0; + virtual void writeFrameData(std::string &&frame_data) = 0; - virtual QByteArray readAll() = 0; - virtual qint64 write(const char *data, qint64 max_size) = 0; - virtual void writeMessageBegin() = 0; - virtual void writeMessageEnd() = 0; virtual void ignoreSslErrors() = 0; virtual void onParseDataException(const shv::chainpack::ParseException &); @@ -52,11 +103,11 @@ class SHVIOTQT_DECL_EXPORT Socket : public QObject Q_SIGNAL void connected(); Q_SIGNAL void disconnected(); Q_SIGNAL void readyRead(); - Q_SIGNAL void bytesWritten(qint64 bytes); + //Q_SIGNAL void bytesWritten(qint64 bytes); Q_SIGNAL void socketReset(); - Q_SIGNAL void stateChanged(QAbstractSocket::SocketState state); + Q_SIGNAL void stateChanged(QAbstractSocket::SocketState state); Q_SIGNAL void error(QAbstractSocket::SocketError socket_error); Q_SIGNAL void sslErrors(const QList &errors); }; @@ -69,30 +120,8 @@ class SHVIOTQT_DECL_EXPORT TcpSocket : public Socket public: TcpSocket(QTcpSocket *socket, QObject *parent = nullptr); - void connectToHost(const QUrl &url) override; - void close() override; - void abort() override; - QAbstractSocket::SocketState state() const override; - QString errorString() const override; - QHostAddress peerAddress() const override; - quint16 peerPort() const override; - QByteArray readAll() override; - qint64 write(const char *data, qint64 max_size) override; - void writeMessageBegin() override; - void writeMessageEnd() override; - void ignoreSslErrors() override; - -protected: - QTcpSocket *m_socket = nullptr; -}; - -class SHVIOTQT_DECL_EXPORT LocalSocket : public Socket -{ - Q_OBJECT - - using Super = Socket; -public: - LocalSocket(QLocalSocket *socket, QObject *parent = nullptr); + std::string readFrameData() override; + void writeFrameData(std::string &&frame_data) override; void connectToHost(const QUrl &url) override; void close() override; @@ -101,13 +130,14 @@ class SHVIOTQT_DECL_EXPORT LocalSocket : public Socket QString errorString() const override; QHostAddress peerAddress() const override; quint16 peerPort() const override; - QByteArray readAll() override; - qint64 write(const char *data, qint64 max_size) override; - void writeMessageBegin() override; - void writeMessageEnd() override; void ignoreSslErrors() override; protected: - QLocalSocket *m_socket = nullptr; + void onDataReadyRead(); + void flushWriteBuffer(); +protected: + QTcpSocket *m_socket = nullptr; + StreamFrameReader m_frameReader; + StreamFrameWriter m_frameWriter; }; #ifndef QT_NO_SSL diff --git a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h index 58a2fb4c5..17b4e79be 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h @@ -47,11 +47,10 @@ class SHVIOTQT_DECL_EXPORT SocketRpcConnection : public QObject, public shv::cha protected: // RpcDriver interface bool isOpen() Q_DECL_OVERRIDE; - int64_t writeFrameData(std::string &&frame_data) override; + void writeFrameData(std::string &&frame_data) override; Socket* socket(); void onReadyRead(); - void onBytesWritten(); void onParseDataException(const shv::chainpack::ParseException &e) override; protected: diff --git a/libshviotqt/include/shv/iotqt/rpc/websocket.h b/libshviotqt/include/shv/iotqt/rpc/websocket.h index 0b9ccfb96..dc823792a 100644 --- a/libshviotqt/include/shv/iotqt/rpc/websocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/websocket.h @@ -17,6 +17,9 @@ class SHVIOTQT_DECL_EXPORT WebSocket : public Socket public: WebSocket(QWebSocket *socket, QObject *parent = nullptr); + std::string readFrameData() override; + void writeFrameData(std::string &&frame_data) override; + void connectToHost(const QUrl &url) override; void close() override; void abort() override; @@ -24,18 +27,16 @@ class SHVIOTQT_DECL_EXPORT WebSocket : public Socket QString errorString() const override; QHostAddress peerAddress() const override; quint16 peerPort() const override; - QByteArray readAll() override; - qint64 write(const char *data, qint64 data_size) override; - void writeMessageBegin() override; - void writeMessageEnd() override; void ignoreSslErrors() override; private: + void flushWriteBuffer(); void onTextMessageReceived(const QString &message); void onBinaryMessageReceived(const QByteArray &message); private: QWebSocket *m_socket = nullptr; - QByteArray m_readBuffer; - QByteArray m_writeBuffer; + + StreamFrameReader m_frameReader; + StreamFrameWriter m_frameWriter; }; } // namespace rpc diff --git a/libshviotqt/src/rpc/clientconnection.cpp b/libshviotqt/src/rpc/clientconnection.cpp index 083ec1285..89e69c110 100644 --- a/libshviotqt/src/rpc/clientconnection.cpp +++ b/libshviotqt/src/rpc/clientconnection.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -207,9 +208,11 @@ void ClientConnection::open() #endif } else if(scheme == Socket::Scheme::LocalSocket) { - socket = new LocalSocket(new QLocalSocket()); + socket = new LocalSocket(new QLocalSocket(), LocalSocket::Protocol::Stream); + } + else if(scheme == Socket::Scheme::LocalSocketSerial) { + socket = new LocalSocket(new QLocalSocket(), LocalSocket::Protocol::Serial); } - #ifdef QT_SERIALPORT_LIB else if(scheme == Socket::Scheme::SerialPort) { socket = new SerialPortSocket(new QSerialPort()); @@ -290,7 +293,7 @@ void ClientConnection::sendRpcMessage(const cp::RpcMessage &rpc_msg) << std::string_view(m_rawRpcMessageLog? rpc_msg.toCpon(): rpc_msg.toPrettyString()).substr(0, MAX_LOG_LEN); } } - sendRpcMessage(rpc_msg); + Super::sendRpcMessage(rpc_msg); } void ClientConnection::onRpcMessageReceived(const chainpack::RpcMessage &rpc_msg) diff --git a/libshviotqt/src/rpc/localsocket.cpp b/libshviotqt/src/rpc/localsocket.cpp new file mode 100644 index 000000000..9a4f7bb29 --- /dev/null +++ b/libshviotqt/src/rpc/localsocket.cpp @@ -0,0 +1,176 @@ +#include + +#include + +#include +#include + +namespace shv { +namespace iotqt { +namespace rpc { + +//====================================================== +// LocalSocket +//====================================================== +static QAbstractSocket::SocketState LocalSocket_convertState(QLocalSocket::LocalSocketState state) +{ + switch (state) { + case QLocalSocket::UnconnectedState: + return QAbstractSocket::UnconnectedState; + case QLocalSocket::ConnectingState: + return QAbstractSocket::ConnectingState; + case QLocalSocket::ConnectedState: + return QAbstractSocket::ConnectedState; + case QLocalSocket::ClosingState: + return QAbstractSocket::ClosingState; + } + return QAbstractSocket::UnconnectedState; +} + +LocalSocket::LocalSocket(QLocalSocket *socket, Protocol protocol, QObject *parent) + : Super(parent) + , m_socket(socket) +{ + if (protocol == Protocol::Serial) { + m_frameReader = new SerialFrameReader(); + m_frameWriter = new SerialFrameWriter(); + } + else { + m_frameReader = new StreamFrameReader(); + m_frameWriter = new StreamFrameWriter(); + } + m_socket->setParent(this); + + connect(m_socket, &QLocalSocket::connected, this, &Socket::connected); + connect(m_socket, &QLocalSocket::disconnected, this, &Socket::disconnected); + connect(m_socket, &QLocalSocket::readyRead, this, &LocalSocket::onDataReadyRead); + connect(m_socket, &QLocalSocket::bytesWritten, this, &LocalSocket::flushWriteBuffer); + connect(m_socket, &QLocalSocket::stateChanged, this, [this](QLocalSocket::LocalSocketState state) { + emit stateChanged(LocalSocket_convertState(state)); + }); + connect(m_socket, &QLocalSocket::errorOccurred, this, [this](QLocalSocket::LocalSocketError socket_error) { + switch (socket_error) { + case QLocalSocket::ConnectionRefusedError: + emit error(QAbstractSocket::ConnectionRefusedError); + break; + case QLocalSocket::PeerClosedError: + emit error(QAbstractSocket::RemoteHostClosedError); + break; + case QLocalSocket::ServerNotFoundError: + emit error(QAbstractSocket::HostNotFoundError); + break; + case QLocalSocket::SocketAccessError: + emit error(QAbstractSocket::SocketAddressNotAvailableError); + break; + case QLocalSocket::SocketResourceError: + emit error(QAbstractSocket::SocketResourceError); + break; + case QLocalSocket::SocketTimeoutError: + emit error(QAbstractSocket::SocketTimeoutError); + break; + case QLocalSocket::DatagramTooLargeError: + emit error(QAbstractSocket::DatagramTooLargeError); + break; + case QLocalSocket::ConnectionError: + emit error(QAbstractSocket::NetworkError); + break; + case QLocalSocket::UnsupportedSocketOperationError: + emit error(QAbstractSocket::UnsupportedSocketOperationError); + break; + case QLocalSocket::UnknownSocketError: + emit error(QAbstractSocket::UnknownSocketError); + break; + case QLocalSocket::OperationError: + emit error(QAbstractSocket::OperationError); + break; + } + }); +} + +LocalSocket::~LocalSocket() +{ + delete m_frameReader; + delete m_frameWriter; +} + +std::string LocalSocket::readFrameData() +{ + if(m_frameReader->isEmpty()) + return {}; + return m_frameReader->getFrame(); +} + +void LocalSocket::writeFrameData(std::string &&frame_data) +{ + m_frameWriter->addFrame(std::move(frame_data)); + flushWriteBuffer(); +} + +void LocalSocket::connectToHost(const QUrl &url) +{ + m_socket->connectToServer(url.path()); +} + +void LocalSocket::close() +{ + m_socket->close(); +} + +void LocalSocket::abort() +{ + m_socket->abort(); +} + +QAbstractSocket::SocketState LocalSocket::state() const +{ + return LocalSocket_convertState(m_socket->state()); +} + +QString LocalSocket::errorString() const +{ + return m_socket->errorString(); +} + +QHostAddress LocalSocket::peerAddress() const +{ + return QHostAddress(m_socket->serverName()); +} + +quint16 LocalSocket::peerPort() const +{ + return 0; +} + +void LocalSocket::ignoreSslErrors() +{ +} + +void LocalSocket::onDataReadyRead() +{ + auto ba = m_socket->readAll(); + std::string_view escaped_data(ba.constData(), ba.size()); + m_frameReader->addData(escaped_data); + if (!m_frameReader->isEmpty()) { + emit readyRead(); + } +} + +void LocalSocket::flushWriteBuffer() +{ + while (true) { + auto data = m_frameWriter->getMessageDataToWrite(); + if (data.isEmpty()) + break; + auto n = m_socket->write(data); + if (n > 0 && n < data.size()) { + data = data.mid(n); + m_frameWriter->pushUnwrittenMessageData(data); + } + } + m_socket->flush(); +} + + +} // namespace rpc +} // namespace iotqt +} // namespace shv diff --git a/libshviotqt/src/rpc/serialportsocket.cpp b/libshviotqt/src/rpc/serialportsocket.cpp index 73df577ad..199643885 100644 --- a/libshviotqt/src/rpc/serialportsocket.cpp +++ b/libshviotqt/src/rpc/serialportsocket.cpp @@ -7,15 +7,166 @@ #include #include -#include -#include - #define logSerialPortSocketD() nCDebug("SerialPortSocket") #define logSerialPortSocketM() nCMessage("SerialPortSocket") #define logSerialPortSocketW() nCWarning("SerialPortSocket") +using namespace std; + namespace shv::iotqt::rpc { +//====================================================== +// SerialFrameReader +//====================================================== +enum EscCodes: uint8_t { + STX = 0xA2, + ETX = 0xA3, + ATX = 0xA4, + ESC = 0xAA, + ESTX = 0x02, + EETX = 0x03, + EATX = 0x04, + EESC = 0x0A, +}; + +void SerialFrameReader::addData(std::string_view data) +{ + auto add_byte = [this](string &buff, uint8_t b) { + m_crcDigest.add(b); + if (inEscape()) { + switch (b) { + case ESTX: buff += static_cast(STX); break; + case EETX: buff += static_cast(ETX); break; + case EATX: buff += static_cast(ATX); break; + case EESC: buff += static_cast(ESC); break; + default: throw std::runtime_error("Invalid escap sequention"); + } + } + else { + if (b != ESC) { + buff += static_cast(b); + } + } + }; + for (uint8_t b : data) { + if (b == STX) { + setState(ReadState::WaitingForEtx); + m_recentByte = b; + continue; + } + if (b == ATX) { + setState(ReadState::WaitingForStx); + m_recentByte = b; + continue; + } + switch (m_readState) { + case ReadState::WaitingForStx: { + if (b == STX) { + setState(ReadState::WaitingForEtx); + } + m_recentByte = b; + continue; + } + case ReadState::WaitingForEtx: { + if (b == ETX) { + if (m_withCrcCheck) { + setState(ReadState::WaitingForCrc); + } + else { + finishFrame(); + } + continue; + } + add_byte(m_readBuffer, b); + m_recentByte = b; + continue; + } + case ReadState::WaitingForCrc: { + add_byte(m_crcBuffer, b); + m_recentByte = b; + if (m_crcBuffer.size() == 4) { + finishFrame(); + } + continue; + } + } + } +} + +bool SerialFrameReader::inEscape() const +{ + return m_recentByte == ESC; +} + +void SerialFrameReader::setState(ReadState state) +{ + m_readState = state; + switch (state) { + case ReadState::WaitingForStx: { + break; + } + case ReadState::WaitingForEtx: { + m_readBuffer = {}; + break; + } + case ReadState::WaitingForCrc: { + m_crcBuffer = {}; + break; + } + } +} + +void SerialFrameReader::finishFrame() +{ + if (m_withCrcCheck) { + Q_ASSERT(m_crcBuffer.size() == 4); + shv::chainpack::crc32_t msg_crc = 0; + for(uint8_t bb : m_crcBuffer) { + msg_crc <<= 8; + msg_crc += bb; + } + //logSerialPortSocketD() << "crc data:" << m_crcBuffer.toHex().toStdString(); + logSerialPortSocketD() << "crc received:" << shv::chainpack::utils::intToHex(msg_crc); + logSerialPortSocketD() << "crc computed:" << shv::chainpack::utils::intToHex(m_crcDigest.remainder()); + if(m_crcDigest.remainder() != msg_crc) { + logSerialPortSocketD() << "crc OK"; + } + } + m_frames.push_back(std::move(m_readBuffer)); + setState(ReadState::WaitingForStx); +} + +//====================================================== +// SerialFrameWriter +//====================================================== +void SerialFrameWriter::addFrame(std::string &&frame_data) +{ + QByteArray data_to_write; + auto write_escaped = [&data_to_write](uint8_t b) { + switch (b) { + case STX: data_to_write += static_cast(ESC); data_to_write += static_cast(ESTX); break; + case ETX: data_to_write += static_cast(ESC); data_to_write += static_cast(EETX); break; + case ATX: data_to_write += static_cast(ESC); data_to_write += static_cast(EATX); break; + case ESC: data_to_write += static_cast(ESC); data_to_write += static_cast(EESC); break; + default: data_to_write += static_cast(b); break; + } + }; + data_to_write += static_cast(STX); + for(uint8_t b : frame_data) { + write_escaped(b); + } + data_to_write += static_cast(ETX); + if (m_withCrcCheck) { + shv::chainpack::Crc32Posix crc_digest; + crc_digest.add(frame_data.data(), frame_data.size()); + auto crc = crc_digest.remainder(); + for (int i = 0; i < 4; ++i) { + write_escaped((crc >> (3 - i)) & 0xff); + } + } + m_messagesToWrite << data_to_write; +} + //====================================================== // SerialPortSocket //====================================================== @@ -25,8 +176,8 @@ SerialPortSocket::SerialPortSocket(QSerialPort *port, QObject *parent) { m_port->setParent(this); - connect(m_port, &QSerialPort::readyRead, this, &SerialPortSocket::onSerialDataReadyRead); - connect(m_port, &QSerialPort::bytesWritten, this, &Socket::bytesWritten); + connect(m_port, &QSerialPort::readyRead, this, &SerialPortSocket::onDataReadyRead); + connect(m_port, &QSerialPort::bytesWritten, this, &SerialPortSocket::flushWriteBuffer); connect(m_port, &QSerialPort::errorOccurred, this, [this](QSerialPort::SerialPortError port_error) { switch (port_error) { case QSerialPort::NoError: @@ -83,9 +234,9 @@ void SerialPortSocket::setReceiveTimeout(int millis) m_readDataTimeout = new QTimer(this); m_readDataTimeout->setSingleShot(true); connect(m_readDataTimeout, &QTimer::timeout, this, [this]() { - if(m_readMessageState != ReadMessageState::WaitingForStx) { - setReadMessageError(ReadMessageError::ErrorTimeout); - } + //if(m_readMessageState != ReadMessageState::WaitingForStx) { + // setReadMessageError(ReadMessageError::ErrorTimeout); + //} }); } m_readDataTimeout->setInterval(millis); @@ -125,8 +276,7 @@ void SerialPortSocket::abort() void SerialPortSocket::reset() { - writeMessageBegin(); - writeMessageEnd(); + writeFrameData({}); } QAbstractSocket::SocketState SerialPortSocket::state() const @@ -139,24 +289,6 @@ QString SerialPortSocket::errorString() const return m_port->errorString(); } -QString SerialPortSocket::readMessageErrorString() const -{ - switch(m_readMessageError) { - case ReadMessageError::Ok: return {}; - case ReadMessageError::ErrorEscape: return QStringLiteral("Escaping error"); - case ReadMessageError::ErrorCrc: return QStringLiteral("CRC error"); - case ReadMessageError::ErrorTimeout: return QStringLiteral("Timeout error"); - case ReadMessageError::ErrorUnexpectedStx: return QStringLiteral("Unexpected STX"); - case ReadMessageError::ErrorUnexpectedEtx: return QStringLiteral("Unexpected ETX"); - } - return {}; -} - -SerialPortSocket::ReadMessageError SerialPortSocket::readMessageError() const -{ - return m_readMessageError; -} - QHostAddress SerialPortSocket::peerAddress() const { return QHostAddress(m_port->portName()); @@ -167,227 +299,41 @@ quint16 SerialPortSocket::peerPort() const return 0; } -void SerialPortSocket::onSerialDataReadyRead() +std::string SerialPortSocket::readFrameData() { - if(m_readMessageState != ReadMessageState::WaitingForStx) { - restartReceiveTimeoutTimer(); - } - auto escaped_data = m_port->readAll(); -#if QT_VERSION_MAJOR < 6 - int ix = 0; -#else - qsizetype ix = 0; -#endif - logSerialPortSocketD().nospace() << "Data received:\n" << shv::chainpack::utils::hexDump(escaped_data.constData(), escaped_data.size()); - while(ix < escaped_data.size()) { - switch(m_readMessageState) { - case ReadMessageState::WaitingForStx: { - while (ix < escaped_data.size()) { - auto b = static_cast(escaped_data[ix++]); - if(b == STX) { - logSerialPortSocketD() << "STX received"; - m_readMessageCrc = {}; - setReadMessageState(ReadMessageState::WaitingForEtx); - break; - } - - logSerialPortSocketM() << "Ignoring rubbish:" << shv::chainpack::utils::byteToHex(b) << b << static_cast(b); - } - break; - } - case ReadMessageState::WaitingForEtx: { - while (ix < escaped_data.size()) { - auto b = static_cast(escaped_data[ix++]); - if(b == STX) { - logSerialPortSocketD() << "STX in middle of message data received, restarting read loop"; - setReadMessageState(ReadMessageState::WaitingForStx); - --ix; - break; - } - if(b == ETX && !m_readMessageBuffer.inEscape) { - logSerialPortSocketD() << "ETX received"; - logSerialPortSocketD() << "Message data received:" << m_readMessageBuffer.data.toHex().toStdString(); - setReadMessageState(ReadMessageState::WaitingForCrc); - break; - } - m_readMessageCrc.add(b); - if(auto err = m_readMessageBuffer.append(b); err != ReadMessageError::Ok) { - setReadMessageError(err); - } - } - break; - } - case ReadMessageState::WaitingForCrc: { - while (ix < escaped_data.size()) { - auto b = static_cast(escaped_data[ix++]); - if(b == STX) { - logSerialPortSocketD() << "STX in middle of message data received, restarting read loop"; - setReadMessageState(ReadMessageState::WaitingForStx); - --ix; - break; - } - if(auto err = m_readMessageCrcBuffer.append(b); err != ReadMessageError::Ok) { - setReadMessageError(err); - break; - } - if(!m_readMessageCrcBuffer.inEscape && m_readMessageCrcBuffer.data.size() == sizeof(shv::chainpack::crc32_t)) { - shv::chainpack::crc32_t msg_crc = 0; - for(uint8_t bb : std::as_const(m_readMessageCrcBuffer.data)) { - msg_crc <<= 8; - msg_crc += bb; - } - logSerialPortSocketD() << "crc data:" << m_readMessageCrcBuffer.data.toHex().toStdString(); - logSerialPortSocketD() << "crc received:" << shv::chainpack::utils::intToHex(msg_crc); - logSerialPortSocketD() << "crc computed:" << shv::chainpack::utils::intToHex(m_readMessageCrc.remainder()); - if(m_readMessageCrc.remainder() == msg_crc) { - logSerialPortSocketD() << "crc OK"; - setReadMessageError(ReadMessageError::Ok); - auto data = m_readMessageBuffer.data; - if(data.isEmpty()) { - // RESET message received - logSerialPortSocketM() << "RESET message received"; - emit socketReset(); - } - else { - m_receivedMessages.enqueue(m_readMessageBuffer.data); - emit readyRead(); - } - } - else { - logSerialPortSocketD() << "crc ERROR"; - setReadMessageError(ReadMessageError::ErrorCrc); - } - break; - } - } - break; - } - } - } + if(m_frameReader.isEmpty()) + return {}; + return m_frameReader.getFrame(); } -void SerialPortSocket::setReadMessageState(ReadMessageState st) +void SerialPortSocket::writeFrameData(std::string &&frame_data) { - switch (st) { - case ReadMessageState::WaitingForStx: - logSerialPortSocketD() << "Entering state:" << "WaitingForStx"; - break; - case ReadMessageState::WaitingForEtx: - logSerialPortSocketD() << "Entering state:" << "WaitingForEtx"; - m_readMessageBuffer.clear(); - restartReceiveTimeoutTimer(); - break; - case ReadMessageState::WaitingForCrc: - logSerialPortSocketD() << "Entering state:" << "WaitingForCrc"; - m_readMessageCrcBuffer.clear(); - break; - } - m_readMessageState = st; + m_frameWriter.addFrame(std::move(frame_data)); + flushWriteBuffer(); } -void SerialPortSocket::setReadMessageError(ReadMessageError err) +void SerialPortSocket::onDataReadyRead() { - m_readMessageError = err; - if(err != ReadMessageError::Ok) - logSerialPortSocketM() << "Set read message error:" << readMessageErrorString(); - setReadMessageState(ReadMessageState::WaitingForStx); + auto ba = m_port->readAll(); + string_view escaped_data(ba.constData(), ba.size()); + m_frameReader.addData(escaped_data); + if (!m_frameReader.isEmpty()) { + emit readyRead(); + } } -qint64 SerialPortSocket::writeBytesEscaped(const char *data, qint64 max_size) +void SerialPortSocket::flushWriteBuffer() { - std::array arr = {char{0}}; - auto set_byte = [&arr](uint8_t b) { - arr[0] = static_cast(b); - }; - qint64 written_cnt = 0; - for(written_cnt = 0; written_cnt < max_size; ++written_cnt) { - auto b = static_cast(data[written_cnt]); - if(m_escWritten) { - //finish escape sequence - switch (b) { - case STX: - set_byte(ESTX); - break; - case ETX: - set_byte(EETX); - break; - case ESC: - set_byte(ESC); - break; - default: - logSerialPortSocketW() << "ESC followed by:" << shv::chainpack::utils::byteToHex(b) << "internal escaping error, data sent will be probably corrupted."; - set_byte(b); - break; - } - } - else { - switch (b) { - case STX: - case ETX: - case ESC: - set_byte(ESC); - --written_cnt; - break; - default: - set_byte(b); - break; - } - } - m_writeMessageCrc.add(arr[0]); - auto n = m_port->write(arr.data(), 1); - if(n < 0) { - return -1; - } - if(n == 0) { + while (true) { + auto data = m_frameWriter.getMessageDataToWrite(); + if (data.isEmpty()) break; - } - if(!m_escWritten && static_cast(arr[0]) == ESC) { - m_escWritten = true; - } - else { - m_escWritten = false; + auto n = m_port->write(data); + if (n > 0 && n < data.size()) { + data = data.mid(n); + m_frameWriter.pushUnwrittenMessageData(data); } } - return written_cnt; -} - -QByteArray SerialPortSocket::readAll() -{ - if(m_receivedMessages.isEmpty()) - return {}; - return m_receivedMessages.dequeue(); -} - -qint64 SerialPortSocket::write(const char *data, qint64 max_size) -{ - return writeBytesEscaped(data, max_size); -} - -void SerialPortSocket::writeMessageBegin() -{ - logSerialPortSocketD() << "STX sent"; - m_writeMessageCrc = {}; - std::array stx = {static_cast(STX)}; - m_port->write(stx.data(), 1); -} - -void SerialPortSocket::writeMessageEnd() -{ - logSerialPortSocketD() << "ETX sent"; - std::array etx = {static_cast(ETX)}; - m_port->write(etx.data(), 1); - auto crc = m_writeMessageCrc.remainder(); - static constexpr size_t N = sizeof(shv::chainpack::crc32_t); - QByteArray crc_ba(N, 0); - for(size_t i = 0; i < N; i++) { -#if QT_VERSION_MAJOR < 6 - crc_ba[static_cast(N - i - 1)] = static_cast(crc % 256); -#else - crc_ba[N - i - 1] = static_cast(crc % 256); -#endif - crc /= 256; - } - writeBytesEscaped(crc_ba.constData(), crc_ba.size()); m_port->flush(); } @@ -419,42 +365,4 @@ void SerialPortSocket::onParseDataException(const chainpack::ParseException &) // nothing to do } -SerialPortSocket::ReadMessageError SerialPortSocket::UnescapeBuffer::append(uint8_t b) -{ - if(b == STX) { - return ReadMessageError::ErrorUnexpectedStx; - } - if(b == ETX) { - return ReadMessageError::ErrorUnexpectedEtx; - } - if(inEscape) { - if(b == ESTX) { - data.append(static_cast(STX)); - } - else if(b == EETX) { - data.append(static_cast(ETX)); - } - else if(b == ESC) { - data.append(static_cast(ESC)); - } - else { - return ReadMessageError::ErrorEscape; - } - inEscape = false; - return ReadMessageError::Ok; - } - if(b == ESC) { - inEscape = true; - return ReadMessageError::Ok; - } - data.append(static_cast(b)); - return ReadMessageError::Ok; -} - -void SerialPortSocket::UnescapeBuffer::clear() -{ - data.clear(); - inEscape = false; -} - } diff --git a/libshviotqt/src/rpc/socket.cpp b/libshviotqt/src/rpc/socket.cpp index ae7430f32..d3b9c0372 100644 --- a/libshviotqt/src/rpc/socket.cpp +++ b/libshviotqt/src/rpc/socket.cpp @@ -1,18 +1,67 @@ #include #include +#include +#include #include #include #include #include #include -#include #include #include namespace shv::iotqt::rpc { +//====================================================== +// StreamFrameReader +//====================================================== +void StreamFrameReader::addData(std::string_view data) +{ + m_readBuffer += data; + while (true) { + std::istringstream in(m_readBuffer); + int err_code; + size_t frame_size = chainpack::ChainPackReader::readUIntData(in, &err_code); + if(err_code == CCPCP_RC_BUFFER_UNDERFLOW) { + // not enough data + break; + } + else if(err_code != CCPCP_RC_OK) { + throw std::runtime_error("Read RPC message length error."); + } + auto len = in.tellg(); + if (len <= 0) { + throw std::runtime_error("Read RPC message length data error."); + } + size_t consumed_len = static_cast(len); + if (consumed_len + frame_size <= m_readBuffer.size()) { + auto frame = std::string(m_readBuffer, consumed_len, frame_size); + m_readBuffer = std::string(std::move(m_readBuffer), consumed_len + frame_size); + m_frames.push_back(std::move(frame)); + } + } +} + +//====================================================== +// StreamFrameWriter +//====================================================== +void StreamFrameWriter::addFrame(std::string &&frame_data) +{ + using namespace shv::chainpack; + std::ostringstream out; + { + ChainPackWriter wr(out); + wr.writeUIntData(frame_data.size() + 1); + } + auto len_data = out.str(); + QByteArray data(len_data.data(), len_data.size()); + data += static_cast(Rpc::ProtocolType::ChainPack); + data.append(std::move(frame_data)); + m_messagesToWrite.append(std::move(data)); +} + //====================================================== // Socket //====================================================== @@ -29,8 +78,9 @@ const char * Socket::schemeToString(Scheme schema) case Scheme::Ssl: return "ssl"; case Scheme::WebSocket: return "ws"; case Scheme::WebSocketSecure: return "wss"; - case Scheme::SerialPort: return "serialport"; - case Scheme::LocalSocket: return "localsocket"; + case Scheme::SerialPort: return "serial"; + case Scheme::LocalSocket: return "unix"; + case Scheme::LocalSocketSerial: return "unixs"; } return ""; } @@ -41,8 +91,9 @@ Socket::Scheme Socket::schemeFromString(const std::string &schema) if(schema == "ssl") return Scheme::Ssl; if(schema == "ws") return Scheme::WebSocket; if(schema == "wss") return Scheme::WebSocketSecure; - if(schema == "serialport") return Scheme::SerialPort; - if(schema == "localsocket") return Scheme::LocalSocket; + if(schema == "serialport" || schema == "serial") return Scheme::SerialPort; + if(schema == "localsocket" || schema == "unix") return Scheme::LocalSocket; + if(schema == "unixs") return Scheme::LocalSocketSerial; return Scheme::Tcp; } @@ -62,8 +113,8 @@ TcpSocket::TcpSocket(QTcpSocket *socket, QObject *parent) connect(m_socket, &QTcpSocket::connected, this, &Socket::connected); connect(m_socket, &QTcpSocket::disconnected, this, &Socket::disconnected); - connect(m_socket, &QTcpSocket::readyRead, this, &Socket::readyRead); - connect(m_socket, &QTcpSocket::bytesWritten, this, &Socket::bytesWritten); + connect(m_socket, &QTcpSocket::readyRead, this, &TcpSocket::onDataReadyRead); + connect(m_socket, &QTcpSocket::bytesWritten, this, &TcpSocket::flushWriteBuffer); connect(m_socket, &QTcpSocket::stateChanged, this, &Socket::stateChanged); #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) connect(m_socket, QOverload::of(&QAbstractSocket::error), this, &Socket::error); @@ -108,153 +159,47 @@ quint16 TcpSocket::peerPort() const return m_socket->peerPort(); } -QByteArray TcpSocket::readAll() -{ - return m_socket->readAll(); -} - -qint64 TcpSocket::write(const char *data, qint64 max_size) -{ - return m_socket->write(data, max_size); -} - -void TcpSocket::writeMessageBegin() +std::string TcpSocket::readFrameData() { + if(m_frameReader.isEmpty()) + return {}; + return m_frameReader.getFrame(); } -void TcpSocket::writeMessageEnd() +void TcpSocket::writeFrameData(std::string &&frame_data) { + m_frameWriter.addFrame(std::move(frame_data)); + flushWriteBuffer(); } void TcpSocket::ignoreSslErrors() { } -//====================================================== -// LocalSocket -//====================================================== -static QAbstractSocket::SocketState LocalSocket_convertState(QLocalSocket::LocalSocketState state) +void TcpSocket::onDataReadyRead() { - switch (state) { - case QLocalSocket::UnconnectedState: - return QAbstractSocket::UnconnectedState; - case QLocalSocket::ConnectingState: - return QAbstractSocket::ConnectingState; - case QLocalSocket::ConnectedState: - return QAbstractSocket::ConnectedState; - case QLocalSocket::ClosingState: - return QAbstractSocket::ClosingState; + auto ba = m_socket->readAll(); + std::string_view escaped_data(ba.constData(), ba.size()); + m_frameReader.addData(escaped_data); + if (!m_frameReader.isEmpty()) { + emit readyRead(); } - return QAbstractSocket::UnconnectedState; + } -LocalSocket::LocalSocket(QLocalSocket *socket, QObject *parent) - : Super(parent) - , m_socket(socket) +void TcpSocket::flushWriteBuffer() { - m_socket->setParent(this); - - connect(m_socket, &QLocalSocket::connected, this, &Socket::connected); - connect(m_socket, &QLocalSocket::disconnected, this, &Socket::disconnected); - connect(m_socket, &QLocalSocket::readyRead, this, &Socket::readyRead); - connect(m_socket, &QLocalSocket::bytesWritten, this, &Socket::bytesWritten); - connect(m_socket, &QLocalSocket::stateChanged, this, [this](QLocalSocket::LocalSocketState state) { - emit stateChanged(LocalSocket_convertState(state)); - }); - connect(m_socket, &QLocalSocket::errorOccurred, this, [this](QLocalSocket::LocalSocketError socket_error) { - switch (socket_error) { - case QLocalSocket::ConnectionRefusedError: - emit error(QAbstractSocket::ConnectionRefusedError); - break; - case QLocalSocket::PeerClosedError: - emit error(QAbstractSocket::RemoteHostClosedError); - break; - case QLocalSocket::ServerNotFoundError: - emit error(QAbstractSocket::HostNotFoundError); - break; - case QLocalSocket::SocketAccessError: - emit error(QAbstractSocket::SocketAddressNotAvailableError); - break; - case QLocalSocket::SocketResourceError: - emit error(QAbstractSocket::SocketResourceError); - break; - case QLocalSocket::SocketTimeoutError: - emit error(QAbstractSocket::SocketTimeoutError); - break; - case QLocalSocket::DatagramTooLargeError: - emit error(QAbstractSocket::DatagramTooLargeError); - break; - case QLocalSocket::ConnectionError: - emit error(QAbstractSocket::NetworkError); - break; - case QLocalSocket::UnsupportedSocketOperationError: - emit error(QAbstractSocket::UnsupportedSocketOperationError); - break; - case QLocalSocket::UnknownSocketError: - emit error(QAbstractSocket::UnknownSocketError); - break; - case QLocalSocket::OperationError: - emit error(QAbstractSocket::OperationError); + while (true) { + auto data = m_frameWriter.getMessageDataToWrite(); + if (data.isEmpty()) break; + auto n = m_socket->write(data); + if (n > 0 && n < data.size()) { + data = data.mid(n); + m_frameWriter.pushUnwrittenMessageData(data); } - }); -} - -void LocalSocket::connectToHost(const QUrl &url) -{ - m_socket->connectToServer(url.path()); -} - -void LocalSocket::close() -{ - m_socket->close(); -} - -void LocalSocket::abort() -{ - m_socket->abort(); -} - -QAbstractSocket::SocketState LocalSocket::state() const -{ - return LocalSocket_convertState(m_socket->state()); -} - -QString LocalSocket::errorString() const -{ - return m_socket->errorString(); -} - -QHostAddress LocalSocket::peerAddress() const -{ - return QHostAddress(m_socket->serverName()); -} - -quint16 LocalSocket::peerPort() const -{ - return 0; -} - -QByteArray LocalSocket::readAll() -{ - return m_socket->readAll(); -} - -qint64 LocalSocket::write(const char *data, qint64 max_size) -{ - return m_socket->write(data, max_size); -} - -void LocalSocket::writeMessageBegin() -{ -} - -void LocalSocket::writeMessageEnd() -{ -} - -void LocalSocket::ignoreSslErrors() -{ + } + m_socket->flush(); } //====================================================== diff --git a/libshviotqt/src/rpc/socketrpcconnection.cpp b/libshviotqt/src/rpc/socketrpcconnection.cpp index 1c85219e3..622b1e891 100644 --- a/libshviotqt/src/rpc/socketrpcconnection.cpp +++ b/libshviotqt/src/rpc/socketrpcconnection.cpp @@ -56,9 +56,6 @@ void SocketRpcConnection::setSocket(Socket *socket) bool is_test_run = QCoreApplication::instance() == nullptr; connect(socket, &Socket::readyRead, this, &SocketRpcConnection::onReadyRead, is_test_run? Qt::AutoConnection: Qt::QueuedConnection); connect(socket, &Socket::readyRead, this, &SocketRpcConnection::socketDataReadyRead, is_test_run? Qt::AutoConnection: Qt::QueuedConnection); - // queued connection here is to write data in next event loop, not directly when previous chunk is written - // possibly not needed, its my feeling to do it this way - connect(socket, &Socket::bytesWritten, this, &SocketRpcConnection::onBytesWritten, is_test_run? Qt::AutoConnection: Qt::QueuedConnection); connect(socket, &Socket::connected, this, [this]() { shvDebug() << this << "Socket connected!!!"; emit socketConnectedChanged(true); @@ -102,7 +99,7 @@ void SocketRpcConnection::connectToHost(const QUrl &url) void SocketRpcConnection::onReadyRead() { - QByteArray ba = socket()->readAll(); + auto frame_data = socket()->readFrameData(); #ifdef DUMP_DATA_FILE QFile *f = findChild("DUMP_DATA_FILE"); if(f) { @@ -110,12 +107,7 @@ void SocketRpcConnection::onReadyRead() f->flush(); } #endif - onFrameDataRead(ba.toStdString()); -} - -void SocketRpcConnection::onBytesWritten() -{ - logRpcData() << "onBytesWritten()"; + onFrameDataRead(std::move(frame_data)); } void SocketRpcConnection::onParseDataException(const chainpack::ParseException &e) @@ -129,9 +121,9 @@ bool SocketRpcConnection::isOpen() return isSocketConnected(); } -int64_t SocketRpcConnection::writeFrameData(std::string &&frame_data) +void SocketRpcConnection::writeFrameData(std::string &&frame_data) { - return socket()->write(frame_data.data(), frame_data.size()); + socket()->writeFrameData(std::move(frame_data)); } void SocketRpcConnection::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) diff --git a/libshviotqt/src/rpc/websocket.cpp b/libshviotqt/src/rpc/websocket.cpp index 8263b2592..ee5d8d9d6 100644 --- a/libshviotqt/src/rpc/websocket.cpp +++ b/libshviotqt/src/rpc/websocket.cpp @@ -16,7 +16,6 @@ WebSocket::WebSocket(QWebSocket *socket, QObject *parent) connect(m_socket, &QWebSocket::disconnected, this, &Socket::disconnected); connect(m_socket, &QWebSocket::textMessageReceived, this, &WebSocket::onTextMessageReceived); connect(m_socket, &QWebSocket::binaryMessageReceived, this, &WebSocket::onBinaryMessageReceived); - connect(m_socket, &QWebSocket::bytesWritten, this, &Socket::bytesWritten); connect(m_socket, &QWebSocket::stateChanged, this, &Socket::stateChanged); #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) connect(m_socket, &QWebSocket::errorOccurred, this, &Socket::error); @@ -64,33 +63,17 @@ quint16 WebSocket::peerPort() const return m_socket->peerPort(); } -QByteArray WebSocket::readAll() +std::string WebSocket::readFrameData() { - QByteArray ret = m_readBuffer; - m_readBuffer.clear(); - return ret; + if(m_frameReader.isEmpty()) + return {}; + return m_frameReader.getFrame(); } -qint64 WebSocket::write(const char *data, qint64 data_size) +void WebSocket::writeFrameData(std::string &&frame_data) { - QByteArray ba(data, static_cast(data_size)); - m_writeBuffer.append(ba); - return data_size; -} - -void WebSocket::writeMessageBegin() -{ - shvDebug() << __FUNCTION__; - m_writeBuffer.clear(); -} - -void WebSocket::writeMessageEnd() -{ - shvDebug() << __FUNCTION__ << "message len:" << m_writeBuffer.size() << "\n" << m_writeBuffer; - qint64 n = m_socket->sendBinaryMessage(m_writeBuffer); - if(n < m_writeBuffer.size()) - shvError() << "Send message error, only" << n << "bytes written."; - m_socket->flush(); + m_frameWriter.addFrame(std::move(frame_data)); + flushWriteBuffer(); } void WebSocket::ignoreSslErrors() @@ -100,18 +83,37 @@ void WebSocket::ignoreSslErrors() #endif } +void WebSocket::flushWriteBuffer() +{ + while (true) { + auto data = m_frameWriter.getMessageDataToWrite(); + if (data.isEmpty()) + break; + auto n = m_socket->sendBinaryMessage(data); + if (n < data.size()) { + shvError() << "WebSocket message partialy sent, only" << n << "of" << data.size() << "bytes."; + } + } + m_socket->flush(); +} + void WebSocket::onTextMessageReceived(const QString &message) { shvDebug() << "text message received:" << message; - m_readBuffer.append(message.toUtf8()); - emit readyRead(); + auto ba = message.toUtf8(); + m_frameReader.addData(std::string_view(ba.constData(), ba.size())); + if (!m_frameReader.isEmpty()) { + emit readyRead(); + } } void WebSocket::onBinaryMessageReceived(const QByteArray &message) { shvDebug() << "binary message received:" << message; - m_readBuffer.append(message); - emit readyRead(); + m_frameReader.addData(std::string_view(message.constData(), message.size())); + if (!m_frameReader.isEmpty()) { + emit readyRead(); + } } } // namespace shv diff --git a/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp b/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp index 15a52fadb..6801b482d 100644 --- a/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp +++ b/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp @@ -84,7 +84,7 @@ DOCTEST_TEST_CASE("Send") auto data2 = data1 + QByteArray::fromStdString(extra_rubbish); rec_msg = {}; serial->setDataToReceive(data2); - REQUIRE(socket->readMessageError() == SerialPortSocket::ReadMessageError::Ok); + //REQUIRE(socket->readMessageError() == SerialPortSocket::ReadMessageError::Ok); REQUIRE(rec_msg.value() == rq.value()); } } @@ -103,14 +103,14 @@ DOCTEST_TEST_CASE("Test CRC error") rq.setParams(123); serial->clearWrittenData(); - conn.sendRpcMessage(rq); + conn.sendRpcMessage(rq); auto data = serial->writtenData(); data[5] = ~data[5]; serial->setDataToReceive(data); - REQUIRE(socket->readMessageError() == SerialPortSocket::ReadMessageError::ErrorCrc); + REQUIRE(socket->readFrameData().empty()); } - +/* DOCTEST_TEST_CASE("Test RESET message") { MockRpcConnection conn; @@ -125,3 +125,4 @@ DOCTEST_TEST_CASE("Test RESET message") serial->setDataToReceive(data); REQUIRE(reset_received == true); } +*/ From c63cf63747f2525ad9f11c7906846fb196d3434e Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 28 Jan 2024 12:02:00 +0100 Subject: [PATCH 04/17] Connection user and password can be specified in query part of URL --- libshviotqt/src/rpc/clientconnection.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/libshviotqt/src/rpc/clientconnection.cpp b/libshviotqt/src/rpc/clientconnection.cpp index 89e69c110..d62e9fe0c 100644 --- a/libshviotqt/src/rpc/clientconnection.cpp +++ b/libshviotqt/src/rpc/clientconnection.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef QT_SERIALPORT_LIB #include #include @@ -64,13 +65,21 @@ QUrl ClientConnection::connectionUrl() const void ClientConnection::setConnectionUrl(const QUrl &url) { + auto query = QUrlQuery(url.query()); m_connectionUrl = url; + m_connectionUrl.setQuery(QUrlQuery()); if(auto user = m_connectionUrl.userName(); !user.isEmpty()) { setUser(user.toStdString()); } + if(auto user = query.queryItemValue("user"); !user.isEmpty()) { + setUser(user.toStdString()); + } if(auto password = m_connectionUrl.password(); !password.isEmpty()) { setPassword(password.toStdString()); } + if(auto password = query.queryItemValue("password"); !password.isEmpty()) { + setPassword(password.toStdString()); + } m_connectionUrl.setUserInfo({}); } @@ -88,11 +97,12 @@ QUrl ClientConnection::connectionUrlFromString(const QString &url_str) { static QVector known_schemes { Socket::schemeToString(Socket::Scheme::Tcp), - Socket::schemeToString(Socket::Scheme::Ssl), - Socket::schemeToString(Socket::Scheme::WebSocket), - Socket::schemeToString(Socket::Scheme::WebSocketSecure), - Socket::schemeToString(Socket::Scheme::SerialPort), - Socket::schemeToString(Socket::Scheme::LocalSocket), + Socket::schemeToString(Socket::Scheme::Ssl), + Socket::schemeToString(Socket::Scheme::WebSocket), + Socket::schemeToString(Socket::Scheme::WebSocketSecure), + Socket::schemeToString(Socket::Scheme::SerialPort), + Socket::schemeToString(Socket::Scheme::LocalSocket), + Socket::schemeToString(Socket::Scheme::LocalSocketSerial), }; QUrl url(url_str); if(!known_schemes.contains(url.scheme())) { From 75c7b17655f1fb340cd49e1ecfea5a66a2115878 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 28 Jan 2024 20:16:10 +0100 Subject: [PATCH 05/17] clang tidy, clazy errors fixed --- .../src/chainpack/irpcconnection.cpp | 32 ++++++++----------- libshvchainpack/src/chainpack/rpcdriver.cpp | 8 ++--- libshvchainpack/src/chainpack/rpcmessage.cpp | 2 +- .../src/chainpack/socketrpcdriver.cpp | 8 ++--- .../include/shv/iotqt/rpc/serialportsocket.h | 5 +-- .../shv/iotqt/rpc/socketrpcconnection.h | 2 +- libshviotqt/src/rpc/clientconnection.cpp | 6 ++-- libshviotqt/src/rpc/localsocket.cpp | 10 +++--- libshviotqt/src/rpc/serialportsocket.cpp | 8 ++--- libshviotqt/src/rpc/socket.cpp | 8 ++--- 10 files changed, 40 insertions(+), 49 deletions(-) diff --git a/libshvchainpack/src/chainpack/irpcconnection.cpp b/libshvchainpack/src/chainpack/irpcconnection.cpp index 13bab6adc..7b059d309 100644 --- a/libshvchainpack/src/chainpack/irpcconnection.cpp +++ b/libshvchainpack/src/chainpack/irpcconnection.cpp @@ -133,15 +133,13 @@ int IRpcConnection::callMethodSubscribe(int rq_id, const std::string &shv_path, {Rpc::PAR_METHODS, method}, }); } - else { - return callShvMethod(rq_id - , Rpc::DIR_BROKER_APP - , Rpc::METH_SUBSCRIBE - , RpcValue::Map{ - {Rpc::PAR_PATH, shv_path}, - {Rpc::PAR_METHOD, std::move(method)}, - }); - } + return callShvMethod(rq_id + , Rpc::DIR_BROKER_APP + , Rpc::METH_SUBSCRIBE + , RpcValue::Map{ + {Rpc::PAR_PATH, shv_path}, + {Rpc::PAR_METHOD, std::move(method)}, + }); } int IRpcConnection::callMethodUnsubscribe(const std::string &shv_path, std::string method) @@ -163,15 +161,13 @@ int IRpcConnection::callMethodUnsubscribe(int rq_id, const std::string &shv_path {Rpc::PAR_METHODS, method}, }); } - else { - return callShvMethod(rq_id - , Rpc::DIR_BROKER_APP - , Rpc::METH_UNSUBSCRIBE - , RpcValue::Map{ - {Rpc::PAR_PATH, shv_path}, - {Rpc::PAR_METHOD, std::move(method)}, - }); - } + return callShvMethod(rq_id + , Rpc::DIR_BROKER_APP + , Rpc::METH_UNSUBSCRIBE + , RpcValue::Map{ + {Rpc::PAR_PATH, shv_path}, + {Rpc::PAR_METHOD, std::move(method)}, + }); } } // namespace shv diff --git a/libshvchainpack/src/chainpack/rpcdriver.cpp b/libshvchainpack/src/chainpack/rpcdriver.cpp index 536ac7ceb..bd821a490 100644 --- a/libshvchainpack/src/chainpack/rpcdriver.cpp +++ b/libshvchainpack/src/chainpack/rpcdriver.cpp @@ -93,11 +93,9 @@ std::string RpcDriver::frameToPrettyCpon(const RpcFrame &frame) auto msg = frame.toRpcMessage(&errmsg); return msg.toCpon(); } - else { - auto s = frame.meta.toPrettyString(); - s += " ... " + std::to_string(frame.data.size()) + " bytes of data ... "; - return s; - } + auto s = frame.meta.toPrettyString(); + s += " ... " + std::to_string(frame.data.size()) + " bytes of data ... "; + return s; } } // namespace shv diff --git a/libshvchainpack/src/chainpack/rpcmessage.cpp b/libshvchainpack/src/chainpack/rpcmessage.cpp index ca133375a..84ebe5b55 100644 --- a/libshvchainpack/src/chainpack/rpcmessage.cpp +++ b/libshvchainpack/src/chainpack/rpcmessage.cpp @@ -85,7 +85,7 @@ RpcFrame RpcFrame::fromChainPack(std::string &&frame_data) auto pos = in.tellg(); if(pos < 0) throw ParseException(CCPCP_RC_MALFORMED_INPUT, "Metadata missing", -1); - auto data = std::string(std::move(frame_data), pos); + auto data = std::string(frame_data, pos); return RpcFrame(std::move(meta), std::move(data)); } diff --git a/libshvchainpack/src/chainpack/socketrpcdriver.cpp b/libshvchainpack/src/chainpack/socketrpcdriver.cpp index a40e9a6ad..7cbdf0f92 100644 --- a/libshvchainpack/src/chainpack/socketrpcdriver.cpp +++ b/libshvchainpack/src/chainpack/socketrpcdriver.cpp @@ -60,7 +60,7 @@ void SocketRpcDriver::writeFrameData(std::string &&frame_data) return; } if (m_writeBuffer.size() + frame_data.size() < m_maxWriteBufferLength) { - m_writeBuffer += std::move(frame_data); + m_writeBuffer += frame_data; flush(); } } @@ -186,9 +186,9 @@ void SocketRpcDriver::exec() // not enough data break; } - else if(err_code == CCPCP_RC_OK) { + if(err_code == CCPCP_RC_OK) { auto consumed_len = in2.tellg(); - m_readBuffer = std::string(std::move(m_readBuffer), consumed_len); + m_readBuffer = std::string(m_readBuffer, consumed_len); m_readFrameSize = frame_size; } else { @@ -200,7 +200,7 @@ void SocketRpcDriver::exec() } if (m_readFrameSize > 0 && m_readFrameSize <= m_readBuffer.size()) { auto frame = std::string(m_readBuffer, 0, m_readFrameSize); - m_readBuffer = std::string(std::move(m_readBuffer), m_readFrameSize); + m_readBuffer = std::string(m_readBuffer, m_readFrameSize); onFrameDataRead(std::move(frame)); } if (m_readFrameSize == 0 || m_readFrameSize > m_readBuffer.size()) { diff --git a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h index 856f86346..282897ce0 100644 --- a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h @@ -12,12 +12,13 @@ class QTimer; namespace shv::iotqt::rpc { class SerialFrameReader : public FrameReader { +public: + enum class ReadState {WaitingForStx, WaitingForEtx, WaitingForCrc}; public: ~SerialFrameReader() override = default; void addData(std::string_view data) override; -private: - enum class ReadState {WaitingForStx, WaitingForEtx, WaitingForCrc}; + ReadState readState() const { return m_readState; } private: bool inEscape() const; void setState(ReadState state); diff --git a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h index 17b4e79be..c679900a1 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h @@ -30,7 +30,7 @@ class SHVIOTQT_DECL_EXPORT SocketRpcConnection : public QObject, public shv::cha void connectToHost(const QUrl &url); - void sendRpcMessage(const chainpack::RpcMessage &rpc_msg); + void sendRpcMessage(const chainpack::RpcMessage &rpc_msg) override; void closeSocket(); void abortSocket(); diff --git a/libshviotqt/src/rpc/clientconnection.cpp b/libshviotqt/src/rpc/clientconnection.cpp index d62e9fe0c..0306f1c67 100644 --- a/libshviotqt/src/rpc/clientconnection.cpp +++ b/libshviotqt/src/rpc/clientconnection.cpp @@ -532,10 +532,8 @@ const string &ClientConnection::pingShvPath() const static std::string s = ".app"; return s; } - else { - static std::string s = ".broker/app"; - return s; - } + static std::string s = ".broker/app"; + return s; } ClientConnection::State ClientConnection::state() const diff --git a/libshviotqt/src/rpc/localsocket.cpp b/libshviotqt/src/rpc/localsocket.cpp index 9a4f7bb29..215dbd614 100644 --- a/libshviotqt/src/rpc/localsocket.cpp +++ b/libshviotqt/src/rpc/localsocket.cpp @@ -5,9 +5,7 @@ #include #include -namespace shv { -namespace iotqt { -namespace rpc { +namespace shv::iotqt::rpc { //====================================================== // LocalSocket @@ -171,6 +169,6 @@ void LocalSocket::flushWriteBuffer() } -} // namespace rpc -} // namespace iotqt -} // namespace shv +} // namespace shv::iotqt::rpc + + diff --git a/libshviotqt/src/rpc/serialportsocket.cpp b/libshviotqt/src/rpc/serialportsocket.cpp index 199643885..c57a552be 100644 --- a/libshviotqt/src/rpc/serialportsocket.cpp +++ b/libshviotqt/src/rpc/serialportsocket.cpp @@ -234,9 +234,9 @@ void SerialPortSocket::setReceiveTimeout(int millis) m_readDataTimeout = new QTimer(this); m_readDataTimeout->setSingleShot(true); connect(m_readDataTimeout, &QTimer::timeout, this, [this]() { - //if(m_readMessageState != ReadMessageState::WaitingForStx) { - // setReadMessageError(ReadMessageError::ErrorTimeout); - //} + if(m_frameReader.readState() != SerialFrameReader::ReadState::WaitingForStx) { + reset(); + } }); } m_readDataTimeout->setInterval(millis); @@ -276,7 +276,7 @@ void SerialPortSocket::abort() void SerialPortSocket::reset() { - writeFrameData({}); + //TODO: reset will be implemented when it will be finished in documentation } QAbstractSocket::SocketState SerialPortSocket::state() const diff --git a/libshviotqt/src/rpc/socket.cpp b/libshviotqt/src/rpc/socket.cpp index d3b9c0372..d2e4dd967 100644 --- a/libshviotqt/src/rpc/socket.cpp +++ b/libshviotqt/src/rpc/socket.cpp @@ -28,17 +28,17 @@ void StreamFrameReader::addData(std::string_view data) // not enough data break; } - else if(err_code != CCPCP_RC_OK) { + if(err_code != CCPCP_RC_OK) { throw std::runtime_error("Read RPC message length error."); } auto len = in.tellg(); if (len <= 0) { throw std::runtime_error("Read RPC message length data error."); } - size_t consumed_len = static_cast(len); + auto consumed_len = static_cast(len); if (consumed_len + frame_size <= m_readBuffer.size()) { auto frame = std::string(m_readBuffer, consumed_len, frame_size); - m_readBuffer = std::string(std::move(m_readBuffer), consumed_len + frame_size); + m_readBuffer = std::string(m_readBuffer, consumed_len + frame_size); m_frames.push_back(std::move(frame)); } } @@ -59,7 +59,7 @@ void StreamFrameWriter::addFrame(std::string &&frame_data) QByteArray data(len_data.data(), len_data.size()); data += static_cast(Rpc::ProtocolType::ChainPack); data.append(std::move(frame_data)); - m_messagesToWrite.append(std::move(data)); + m_messagesToWrite.append(data); } //====================================================== From 6b2ad3787533df44a3072fecfebda37a2b258ca5 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 28 Jan 2024 20:34:48 +0100 Subject: [PATCH 06/17] Some nested name-spaces concatenated --- libshvchainpack/include/shv/chainpack/rpcdriver.h | 6 ++---- libshvchainpack/src/chainpack/rpcdriver.cpp | 5 ----- libshviotqt/include/shv/iotqt/rpc/deviceconnection.h | 10 ++++------ libshviotqt/include/shv/iotqt/rpc/localsocket.h | 10 ++++------ .../include/shv/iotqt/rpc/rpcresponsecallback.h | 7 +++---- libshviotqt/include/shv/iotqt/rpc/serverconnection.h | 6 ++---- libshviotqt/include/shv/iotqt/rpc/socket.h | 10 ++++------ .../include/shv/iotqt/rpc/socketrpcconnection.h | 6 ++---- libshviotqt/include/shv/iotqt/rpc/tcpserver.h | 8 +++----- libshviotqt/include/shv/iotqt/rpc/websocket.h | 10 ++++------ libshviotqt/include/shv/iotqt/utils/network.h | 6 ++---- 11 files changed, 30 insertions(+), 54 deletions(-) diff --git a/libshvchainpack/include/shv/chainpack/rpcdriver.h b/libshvchainpack/include/shv/chainpack/rpcdriver.h index 5e3b7f19d..e5c862eb2 100644 --- a/libshvchainpack/include/shv/chainpack/rpcdriver.h +++ b/libshvchainpack/include/shv/chainpack/rpcdriver.h @@ -6,8 +6,7 @@ #include -namespace shv { -namespace chainpack { +namespace shv::chainpack { class ParseException; @@ -41,5 +40,4 @@ class SHVCHAINPACK_DECL_EXPORT RpcDriver static int s_defaultRpcTimeoutMsec; }; -} // namespace chainpack -} // namespace shv +} diff --git a/libshvchainpack/src/chainpack/rpcdriver.cpp b/libshvchainpack/src/chainpack/rpcdriver.cpp index bd821a490..1ef9c7182 100644 --- a/libshvchainpack/src/chainpack/rpcdriver.cpp +++ b/libshvchainpack/src/chainpack/rpcdriver.cpp @@ -8,11 +8,6 @@ #include -#include -#include -#include -#include - #define logRpcRawMsg() nCMessage("RpcRawMsg") #define logRpcData() nCMessage("RpcData") #define logRpcDataW() nCWarning("RpcData") diff --git a/libshviotqt/include/shv/iotqt/rpc/deviceconnection.h b/libshviotqt/include/shv/iotqt/rpc/deviceconnection.h index b1f4c4d82..e8981e015 100644 --- a/libshviotqt/include/shv/iotqt/rpc/deviceconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/deviceconnection.h @@ -2,9 +2,7 @@ #include "clientconnection.h" -namespace shv { -namespace iotqt { -namespace rpc { +namespace shv::iotqt::rpc { class DeviceAppCliOptions; @@ -21,6 +19,6 @@ class SHVIOTQT_DECL_EXPORT DeviceConnection : public ClientConnection void setCliOptions(const DeviceAppCliOptions *cli_opts); }; -} // namespace rpc -} // namespace iotqt -} // namespace shv +} // namespace shv::iotqt::rpc + + diff --git a/libshviotqt/include/shv/iotqt/rpc/localsocket.h b/libshviotqt/include/shv/iotqt/rpc/localsocket.h index 002976c75..a625fed93 100644 --- a/libshviotqt/include/shv/iotqt/rpc/localsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/localsocket.h @@ -3,9 +3,7 @@ #include "socket.h" -namespace shv { -namespace iotqt { -namespace rpc { +namespace shv::iotqt::rpc { class SHVIOTQT_DECL_EXPORT LocalSocket : public Socket { @@ -37,8 +35,8 @@ class SHVIOTQT_DECL_EXPORT LocalSocket : public Socket FrameWriter *m_frameWriter; }; -} // namespace rpc -} // namespace iotqt -} // namespace shv +} // namespace shv::iotqt::rpc + + #endif // SHV_IOTQT_RPC_LOCALSOCKET_H diff --git a/libshviotqt/include/shv/iotqt/rpc/rpcresponsecallback.h b/libshviotqt/include/shv/iotqt/rpc/rpcresponsecallback.h index fba3abb37..e166d460d 100644 --- a/libshviotqt/include/shv/iotqt/rpc/rpcresponsecallback.h +++ b/libshviotqt/include/shv/iotqt/rpc/rpcresponsecallback.h @@ -19,8 +19,7 @@ namespace shv { namespace chainpack { class RpcMessage; class RpcResponse; class RpcError; } -namespace iotqt { -namespace rpc { +namespace iotqt::rpc { class ClientConnection; @@ -90,6 +89,6 @@ class SHVIOTQT_DECL_EXPORT RpcCall : public QObject int m_requestId = 0; }; -} // namespace rpc -} // namespace iotqt +} // namespace iotqt::rpc + } // namespace shv diff --git a/libshviotqt/include/shv/iotqt/rpc/serverconnection.h b/libshviotqt/include/shv/iotqt/rpc/serverconnection.h index 05d472bb3..2652cd788 100644 --- a/libshviotqt/include/shv/iotqt/rpc/serverconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/serverconnection.h @@ -12,9 +12,7 @@ #include -namespace shv { -namespace iotqt { -namespace rpc { +namespace shv::iotqt::rpc { class Socket; @@ -67,5 +65,5 @@ class SHVIOTQT_DECL_EXPORT ServerConnection : public SocketRpcConnection shv::chainpack::RpcValue m_connectionOptions; }; -}}} +} diff --git a/libshviotqt/include/shv/iotqt/rpc/socket.h b/libshviotqt/include/shv/iotqt/rpc/socket.h index 960b27f19..b80401cf6 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socket.h +++ b/libshviotqt/include/shv/iotqt/rpc/socket.h @@ -15,9 +15,7 @@ class QSerialPort; namespace shv::chainpack { class ParseException; } -namespace shv { -namespace iotqt { -namespace rpc { +namespace shv::iotqt::rpc { class FrameReader { public: @@ -156,6 +154,6 @@ class SHVIOTQT_DECL_EXPORT SslSocket : public TcpSocket QSslSocket::PeerVerifyMode m_peerVerifyMode; }; #endif -} // namespace rpc -} // namespace iotqt -} // namespace shv +} // namespace shv::iotqt::rpc + + diff --git a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h index c679900a1..6782b93b8 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h @@ -11,9 +11,7 @@ class QSslError; class QTcpSocket; class QThread; -namespace shv { -namespace iotqt { -namespace rpc { +namespace shv::iotqt::rpc { class Socket; @@ -57,5 +55,5 @@ class SHVIOTQT_DECL_EXPORT SocketRpcConnection : public QObject, public shv::cha Socket *m_socket = nullptr; }; -}}} +} diff --git a/libshviotqt/include/shv/iotqt/rpc/tcpserver.h b/libshviotqt/include/shv/iotqt/rpc/tcpserver.h index 42c94fa63..83ae244ca 100644 --- a/libshviotqt/include/shv/iotqt/rpc/tcpserver.h +++ b/libshviotqt/include/shv/iotqt/rpc/tcpserver.h @@ -7,11 +7,9 @@ #include -namespace shv { namespace chainpack { class RpcMessage; }} +namespace shv::chainpack { class RpcMessage; } -namespace shv { -namespace iotqt { -namespace rpc { +namespace shv::iotqt::rpc { class ServerConnection; @@ -36,5 +34,5 @@ class SHVIOTQT_DECL_EXPORT TcpServer : public QTcpServer std::map m_connections; }; -}}} +} diff --git a/libshviotqt/include/shv/iotqt/rpc/websocket.h b/libshviotqt/include/shv/iotqt/rpc/websocket.h index dc823792a..f48507a31 100644 --- a/libshviotqt/include/shv/iotqt/rpc/websocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/websocket.h @@ -5,9 +5,7 @@ class QWebSocket; -namespace shv { -namespace iotqt { -namespace rpc { +namespace shv::iotqt::rpc { class SHVIOTQT_DECL_EXPORT WebSocket : public Socket { @@ -39,8 +37,8 @@ class SHVIOTQT_DECL_EXPORT WebSocket : public Socket StreamFrameWriter m_frameWriter; }; -} // namespace rpc -} // namespace iotqt -} // namespace shv +} // namespace shv::iotqt::rpc + + #endif // SHV_IOTQT_RPC_WEBSOCKET_H diff --git a/libshviotqt/include/shv/iotqt/utils/network.h b/libshviotqt/include/shv/iotqt/utils/network.h index a1f550ade..59034a6bd 100644 --- a/libshviotqt/include/shv/iotqt/utils/network.h +++ b/libshviotqt/include/shv/iotqt/utils/network.h @@ -6,9 +6,7 @@ class QHostAddress; -namespace shv { -namespace iotqt { -namespace utils { +namespace shv::iotqt::utils { class SHVIOTQT_DECL_EXPORT Network { @@ -20,5 +18,5 @@ class SHVIOTQT_DECL_EXPORT Network static QHostAddress primaryIPv4Address(); }; -}}} +} From cce21a667bd93c138b664f6515b2c198a44ccd16 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 29 Jan 2024 16:08:06 +0100 Subject: [PATCH 07/17] CRC32 lookup table reimplemented as consteval --- libshvchainpack/include/shv/chainpack/crc32.h | 42 +++++++++++-------- libshvchainpack/tests/test_crc32.cpp | 15 ++++++- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/libshvchainpack/include/shv/chainpack/crc32.h b/libshvchainpack/include/shv/chainpack/crc32.h index 7fec72082..a8db268cd 100644 --- a/libshvchainpack/include/shv/chainpack/crc32.h +++ b/libshvchainpack/include/shv/chainpack/crc32.h @@ -2,31 +2,36 @@ #include #include -#include +#include namespace shv::chainpack { using crc32_t = uint32_t; + +// CRC-32/ISO-HDLC constexpr crc32_t CRC_POSIX_POLY_REV = 0xEDB88320L; -template +template +consteval auto make_table() { + auto crc32_for_byte = [](uint8_t b) + { + constexpr auto MSB_MASK = static_cast(0xFF) << ((sizeof(crc32_t) - 1) * 8); + auto r = static_cast(b); + for(int j = 0; j < 8; ++j) + r = (r & 1? 0: POLY) ^ (r >> 1); + return r ^ MSB_MASK; + }; + std::array table; + for(crc32_t i = 0; i < 0x100; ++i) { + table[i] = crc32_for_byte(static_cast(i)); + } + return table; +} + +template class Crc32 { public: - constexpr Crc32() { - auto crc32_for_byte = [](uint8_t b) - { - constexpr auto MSB_MASK = static_cast(0xFF) << ((sizeof(crc32_t) - 1) * 8); - auto r = static_cast(b); - for(int j = 0; j < 8; ++j) - r = (r & 1? 0: POLY_REV) ^ (r >> 1); - return r ^ MSB_MASK; - }; - for(crc32_t i = 0; i < 0x100; ++i) { - m_table[i] = crc32_for_byte(static_cast(i)); - } - } - void add(uint8_t b) { const auto ix = static_cast(m_remainder ^ static_cast(b)); m_remainder = m_table[ix] ^ (m_remainder >> 8); @@ -37,11 +42,14 @@ class Crc32 } } crc32_t remainder() const { return m_remainder; } + void setRemainder(crc32_t rem) { m_remainder = rem; } + void reset() { setRemainder(0); } private: crc32_t m_remainder = 0; - crc32_t m_table[256]; + static constexpr auto m_table = make_table(); }; using Crc32Posix = Crc32; +using Crc32Shv3 = Crc32Posix; } diff --git a/libshvchainpack/tests/test_crc32.cpp b/libshvchainpack/tests/test_crc32.cpp index 9b02794de..710881573 100644 --- a/libshvchainpack/tests/test_crc32.cpp +++ b/libshvchainpack/tests/test_crc32.cpp @@ -20,9 +20,9 @@ DOCTEST_TEST_CASE("CRC on CRC_POSIX_POLY") for(size_t i = 0 ; i < N; ++i) { arr[i] = static_cast(CRC_POSIX_POLY_REV >> (i * 8)); } - auto zip_crc = crc32(0L, Z_NULL, 0); + auto zip_crc = ::crc32(0L, Z_NULL, 0); auto data = reinterpret_cast(arr.data()); - zip_crc = crc32(zip_crc, data, arr.size()); + zip_crc = ::crc32(zip_crc, data, arr.size()); shv::chainpack::Crc32Posix crc; crc.add(arr.data(), arr.size()); @@ -30,6 +30,17 @@ DOCTEST_TEST_CASE("CRC on CRC_POSIX_POLY") REQUIRE(zip_crc == my_crc); } + +DOCTEST_TEST_CASE("CRC SHV3") +{ + shv::chainpack::Crc32Shv3 crc; + vector data = { 0x01,0x8B,0x41,0x41,0x48,0x41,0x49,0x86,0x07,0x66,0x6F,0x6F,0x2F,0x62,0x61,0x72,0x4A,0x86,0x03,0x62,0x61,0x7A,0xFF,0x8A,0x41,0x86,0x05,0x68,0x65,0x6C,0x6C,0x6F,0xFF }; + crc.add(data.data(), data.size()); + auto my_crc = crc.remainder(); + + REQUIRE(0xd7a14e96 == my_crc); +} + DOCTEST_TEST_CASE("CRC on strings") { for(const auto &s : { From 7d5e0f3dc9d383b4ed7c62541b14ddb5df0fe473 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 29 Jan 2024 16:09:29 +0100 Subject: [PATCH 08/17] Socket::flush() reimplemented, CRC32 in SerialPortSocket fixed --- libshvchainpack/include/shv/chainpack/utils.h | 1 + libshvchainpack/src/chainpack/utils.cpp | 15 +++++- .../include/shv/iotqt/rpc/localsocket.h | 2 + .../include/shv/iotqt/rpc/serialportsocket.h | 2 +- libshviotqt/include/shv/iotqt/rpc/socket.h | 20 +++---- libshviotqt/src/rpc/localsocket.cpp | 11 +--- libshviotqt/src/rpc/serialportsocket.cpp | 41 +++++++------- libshviotqt/src/rpc/socket.cpp | 54 ++++++++++++++----- libshviotqt/src/rpc/websocket.cpp | 10 +--- .../test_serialportsocket.cpp | 13 ++++- 10 files changed, 103 insertions(+), 66 deletions(-) diff --git a/libshvchainpack/include/shv/chainpack/utils.h b/libshvchainpack/include/shv/chainpack/utils.h index 9483800cd..07edec4dc 100644 --- a/libshvchainpack/include/shv/chainpack/utils.h +++ b/libshvchainpack/include/shv/chainpack/utils.h @@ -16,6 +16,7 @@ class RpcValue; namespace utils { +SHVCHAINPACK_DECL_EXPORT std::string hexArray(const char *bytes, size_t n); SHVCHAINPACK_DECL_EXPORT std::string hexDump(const char *bytes, size_t n); SHVCHAINPACK_DECL_EXPORT std::string byteToHex( uint8_t i ); SHVCHAINPACK_DECL_EXPORT void byteToHex( std::array &arr, uint8_t i ); diff --git a/libshvchainpack/src/chainpack/utils.cpp b/libshvchainpack/src/chainpack/utils.cpp index 4599a3c84..8796d6fe8 100644 --- a/libshvchainpack/src/chainpack/utils.cpp +++ b/libshvchainpack/src/chainpack/utils.cpp @@ -2,7 +2,6 @@ #include #include -#include using namespace std; @@ -59,6 +58,20 @@ string hexDump(const char *bytes, size_t n) return ret; } +string hexArray(const char *bytes, size_t n) +{ + std::string ret = "["; + for (size_t i = 0; i < n; ++i) { + auto c = bytes[i]; + std::string s = "0x"; + s += byteToHex(static_cast(c)); + if (i > 0) + ret += ','; + ret += s; + } + return ret + ']'; +} + } std::string Utils::removeJsonComments(const std::string &json_str) { diff --git a/libshviotqt/include/shv/iotqt/rpc/localsocket.h b/libshviotqt/include/shv/iotqt/rpc/localsocket.h index a625fed93..32927ceec 100644 --- a/libshviotqt/include/shv/iotqt/rpc/localsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/localsocket.h @@ -3,6 +3,8 @@ #include "socket.h" +class QLocalSocket; + namespace shv::iotqt::rpc { class SHVIOTQT_DECL_EXPORT LocalSocket : public Socket diff --git a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h index 282897ce0..7605a23bc 100644 --- a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h @@ -28,7 +28,7 @@ class SerialFrameReader : public FrameReader { uint8_t m_recentByte = 0; std::string m_readBuffer; std::string m_crcBuffer; - shv::chainpack::Crc32Posix m_crcDigest; + shv::chainpack::Crc32Shv3 m_crcDigest; bool m_withCrcCheck = true; }; diff --git a/libshviotqt/include/shv/iotqt/rpc/socket.h b/libshviotqt/include/shv/iotqt/rpc/socket.h index b80401cf6..963fa218f 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socket.h +++ b/libshviotqt/include/shv/iotqt/rpc/socket.h @@ -10,8 +10,9 @@ #include class QTcpSocket; -class QLocalSocket; -class QSerialPort; +#ifdef WITH_SHV_WEBSOCKETS +class QWebSocket; +#endif namespace shv::chainpack { class ParseException; } @@ -38,17 +39,12 @@ class FrameWriter { public: virtual ~FrameWriter() = default; virtual void addFrame(std::string &&frame_data) = 0; - QByteArray getMessageDataToWrite() { - if (!m_messagesToWrite.empty()) { - return m_messagesToWrite.takeFirst(); - } - return {}; - } - void pushUnwrittenMessageData(QByteArray data) { - m_messagesToWrite.insert(0, data); - } + void flushToDevice(QIODevice *device); +#ifdef WITH_SHV_WEBSOCKETS + void flushToWebSocket(QWebSocket *socket); +#endif protected: - QList m_messagesToWrite; + QList m_messageDataToWrite; }; class StreamFrameReader : public FrameReader { diff --git a/libshviotqt/src/rpc/localsocket.cpp b/libshviotqt/src/rpc/localsocket.cpp index 215dbd614..fed59d4a9 100644 --- a/libshviotqt/src/rpc/localsocket.cpp +++ b/libshviotqt/src/rpc/localsocket.cpp @@ -155,16 +155,7 @@ void LocalSocket::onDataReadyRead() void LocalSocket::flushWriteBuffer() { - while (true) { - auto data = m_frameWriter->getMessageDataToWrite(); - if (data.isEmpty()) - break; - auto n = m_socket->write(data); - if (n > 0 && n < data.size()) { - data = data.mid(n); - m_frameWriter->pushUnwrittenMessageData(data); - } - } + m_frameWriter->flushToDevice(m_socket); m_socket->flush(); } diff --git a/libshviotqt/src/rpc/serialportsocket.cpp b/libshviotqt/src/rpc/serialportsocket.cpp index c57a552be..2b4ad2c20 100644 --- a/libshviotqt/src/rpc/serialportsocket.cpp +++ b/libshviotqt/src/rpc/serialportsocket.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -32,7 +33,6 @@ enum EscCodes: uint8_t { void SerialFrameReader::addData(std::string_view data) { auto add_byte = [this](string &buff, uint8_t b) { - m_crcDigest.add(b); if (inEscape()) { switch (b) { case ESTX: buff += static_cast(STX); break; @@ -77,6 +77,7 @@ void SerialFrameReader::addData(std::string_view data) } continue; } + m_crcDigest.add(b); add_byte(m_readBuffer, b); m_recentByte = b; continue; @@ -107,6 +108,7 @@ void SerialFrameReader::setState(ReadState state) } case ReadState::WaitingForEtx: { m_readBuffer = {}; + m_crcDigest.reset(); break; } case ReadState::WaitingForCrc: { @@ -126,13 +128,21 @@ void SerialFrameReader::finishFrame() msg_crc += bb; } //logSerialPortSocketD() << "crc data:" << m_crcBuffer.toHex().toStdString(); - logSerialPortSocketD() << "crc received:" << shv::chainpack::utils::intToHex(msg_crc); - logSerialPortSocketD() << "crc computed:" << shv::chainpack::utils::intToHex(m_crcDigest.remainder()); + //logSerialPortSocketD() << "crc received:" << shv::chainpack::utils::intToHex(msg_crc); + //logSerialPortSocketD() << "crc computed:" << shv::chainpack::utils::intToHex(m_crcDigest.remainder()); if(m_crcDigest.remainder() != msg_crc) { - logSerialPortSocketD() << "crc OK"; + logSerialPortSocketD() << "crc Error"; + setState(ReadState::WaitingForStx); + return; } } - m_frames.push_back(std::move(m_readBuffer)); + auto protocol = static_cast(shv::chainpack::Rpc::ProtocolType::ChainPack); + if (m_readBuffer.empty() || m_readBuffer[0] != protocol) { + logSerialPortSocketD() << "Protocol type Error"; + setState(ReadState::WaitingForStx); + return; + } + m_frames.emplace_back(m_readBuffer.data(), m_readBuffer.size()); setState(ReadState::WaitingForStx); } @@ -151,20 +161,22 @@ void SerialFrameWriter::addFrame(std::string &&frame_data) default: data_to_write += static_cast(b); break; } }; + auto protocol = static_cast(shv::chainpack::Rpc::ProtocolType::ChainPack); data_to_write += static_cast(STX); + write_escaped(protocol); for(uint8_t b : frame_data) { write_escaped(b); } data_to_write += static_cast(ETX); if (m_withCrcCheck) { - shv::chainpack::Crc32Posix crc_digest; - crc_digest.add(frame_data.data(), frame_data.size()); + shv::chainpack::Crc32Shv3 crc_digest; + crc_digest.add(data_to_write.constData() + 1, data_to_write.size() - 2); auto crc = crc_digest.remainder(); for (int i = 0; i < 4; ++i) { - write_escaped((crc >> (3 - i)) & 0xff); + write_escaped((crc >> ((3 - i) * 8)) & 0xff); } } - m_messagesToWrite << data_to_write; + m_messageDataToWrite << data_to_write; } //====================================================== @@ -324,16 +336,7 @@ void SerialPortSocket::onDataReadyRead() void SerialPortSocket::flushWriteBuffer() { - while (true) { - auto data = m_frameWriter.getMessageDataToWrite(); - if (data.isEmpty()) - break; - auto n = m_port->write(data); - if (n > 0 && n < data.size()) { - data = data.mid(n); - m_frameWriter.pushUnwrittenMessageData(data); - } - } + m_frameWriter.flushToDevice(m_port); m_port->flush(); } diff --git a/libshviotqt/src/rpc/socket.cpp b/libshviotqt/src/rpc/socket.cpp index d691d42cd..306e31324 100644 --- a/libshviotqt/src/rpc/socket.cpp +++ b/libshviotqt/src/rpc/socket.cpp @@ -11,9 +11,48 @@ #include #include #include +#ifdef WITH_SHV_WEBSOCKETS +#include +#endif namespace shv::iotqt::rpc { +//====================================================== +// FrameWriter +//====================================================== +void FrameWriter::flushToDevice(QIODevice *device) +{ + while (!m_messageDataToWrite.isEmpty()) { + auto data = m_messageDataToWrite[0]; + auto n = device->write(data); + if (n <= 0) { + shvWarning() << "Write data error."; + break; + } + if (n < data.size()) { + data = data.mid(n); + m_messageDataToWrite[0] = data; + } + else { + m_messageDataToWrite.takeFirst(); + } + } +} +#ifdef WITH_SHV_WEBSOCKETS +void FrameWriter::flushToWebSocket(QWebSocket *socket) +{ + while (!m_messageDataToWrite.isEmpty()) { + auto data = m_messageDataToWrite[0]; + auto n = socket->sendBinaryMessage(data); + if (n != data.size()) { + shvWarning() << "Write data error."; + break; + } + m_messageDataToWrite.takeFirst(); + } +} +#endif + //====================================================== // StreamFrameReader //====================================================== @@ -58,8 +97,8 @@ void StreamFrameWriter::addFrame(std::string &&frame_data) auto len_data = out.str(); QByteArray data(len_data.data(), len_data.size()); data += static_cast(Rpc::ProtocolType::ChainPack); - data.append(std::move(frame_data)); - m_messagesToWrite.append(data); + data.append(frame_data); + m_messageDataToWrite.append(data); } //====================================================== @@ -188,16 +227,7 @@ void TcpSocket::onDataReadyRead() void TcpSocket::flushWriteBuffer() { - while (true) { - auto data = m_frameWriter.getMessageDataToWrite(); - if (data.isEmpty()) - break; - auto n = m_socket->write(data); - if (n > 0 && n < data.size()) { - data = data.mid(n); - m_frameWriter.pushUnwrittenMessageData(data); - } - } + m_frameWriter.flushToDevice(m_socket); m_socket->flush(); } diff --git a/libshviotqt/src/rpc/websocket.cpp b/libshviotqt/src/rpc/websocket.cpp index ee5d8d9d6..fd88983df 100644 --- a/libshviotqt/src/rpc/websocket.cpp +++ b/libshviotqt/src/rpc/websocket.cpp @@ -85,15 +85,7 @@ void WebSocket::ignoreSslErrors() void WebSocket::flushWriteBuffer() { - while (true) { - auto data = m_frameWriter.getMessageDataToWrite(); - if (data.isEmpty()) - break; - auto n = m_socket->sendBinaryMessage(data); - if (n < data.size()) { - shvError() << "WebSocket message partialy sent, only" << n << "of" << data.size() << "bytes."; - } - } + m_frameWriter.flushToWebSocket(m_socket); m_socket->flush(); } diff --git a/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp b/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp index 6801b482d..a987e051e 100644 --- a/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp +++ b/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp @@ -1,6 +1,7 @@ #include "mockserialport.h" #include "mockrpcconnection.h" +#include #include #include @@ -13,6 +14,10 @@ #define DOCTEST_CONFIG_IMPLEMENT #include +#define logSerialPortSocketD() nCDebug("SerialPortSocket") +#define logSerialPortSocketM() nCMessage("SerialPortSocket") +#define logSerialPortSocketW() nCWarning("SerialPortSocket") + using namespace shv::iotqt::rpc; using namespace shv::chainpack; using namespace std; @@ -58,9 +63,10 @@ DOCTEST_TEST_CASE("Send") for(const auto &p : params) { rq.setParams(p); serial->clearWrittenData(); - rec_msg = {}; - conn.sendRpcMessage(rq); + conn.sendRpcMessage(rq); auto data = serial->writtenData(); + //logSerialPortSocketD() << "msg:" << rq.toCpon(); + //logSerialPortSocketD() << "data:" << utils::hexArray(data.constData(), data.size()); vector rubbish1 = { "", @@ -83,8 +89,11 @@ DOCTEST_TEST_CASE("Send") // add some rubbish auto data2 = data1 + QByteArray::fromStdString(extra_rubbish); rec_msg = {}; + //logSerialPortSocketD().nospace() << "data to send:\n" << utils::hexDump(data2.constData(), data2.size()); serial->setDataToReceive(data2); //REQUIRE(socket->readMessageError() == SerialPortSocket::ReadMessageError::Ok); + //logSerialPortSocketD() << "rec msg:" << rec_msg.value().toCpon(); + //logSerialPortSocketD() << "rq msg:" << rq.value().toCpon(); REQUIRE(rec_msg.value() == rq.value()); } } From 60c7e5cfe252c27e07160ec1955b3adf5d01f87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Kubern=C3=A1t?= Date: Mon, 29 Jan 2024 16:18:50 +0100 Subject: [PATCH 09/17] Revert "CI: Remove blacklisted files" Turns out that we have to have this blacklist, because we still do not have clang-16. This reverts commit a70bb20100962804a6ca3612afdb151b808154c3. --- .github/actions/run-linter/action.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actions/run-linter/action.yml b/.github/actions/run-linter/action.yml index 59aee936f..5fea408c6 100644 --- a/.github/actions/run-linter/action.yml +++ b/.github/actions/run-linter/action.yml @@ -33,7 +33,9 @@ runs: run: | BASE_REF="${{github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before}}" git fetch --depth=1 origin "$BASE_REF" - readarray -t CHANGED_FILES < <(git diff --name-only "$BASE_REF" | grep 'cpp$') + # FIXME: The clang on CI chokes on lambda captures of structured binding variables. Remove the blacklisting of + # the files after the CI gets updated. (AFAIK clang-16). + readarray -t CHANGED_FILES < <(git diff --name-only "$BASE_REF" | grep 'cpp$' | grep -v -e "libshviotqt/tests/serialportsocket/test_serialportsocket.cpp" -e "libshvchainpack/tests/test_rpcvalue.cpp") if [[ "${#CHANGED_FILES[@]}" -eq 0 ]]; then echo "No changed cpp files." exit 0 From 24b97d83a708a93ef33f0d55aaa30cfd3afde22a Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 29 Jan 2024 16:26:35 +0100 Subject: [PATCH 10/17] Clang tidy issues fixed --- libshviotqt/include/shv/iotqt/rpc/serialportsocket.h | 2 +- libshviotqt/include/shv/iotqt/rpc/socket.h | 4 ++-- libshviotqt/src/rpc/serialportsocket.cpp | 4 ++-- libshviotqt/src/rpc/socket.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h index 7605a23bc..5b1cb271c 100644 --- a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h @@ -36,7 +36,7 @@ class SerialFrameWriter : public FrameWriter { public: ~SerialFrameWriter() override = default; - void addFrame(std::string &&frame_data) override; + void addFrame(QByteArrayView frame_data) override; public: bool m_withCrcCheck = true; }; diff --git a/libshviotqt/include/shv/iotqt/rpc/socket.h b/libshviotqt/include/shv/iotqt/rpc/socket.h index 963fa218f..cb4d6fb73 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socket.h +++ b/libshviotqt/include/shv/iotqt/rpc/socket.h @@ -38,7 +38,7 @@ class FrameReader { class FrameWriter { public: virtual ~FrameWriter() = default; - virtual void addFrame(std::string &&frame_data) = 0; + virtual void addFrame(QByteArrayView frame_data) = 0; void flushToDevice(QIODevice *device); #ifdef WITH_SHV_WEBSOCKETS void flushToWebSocket(QWebSocket *socket); @@ -60,7 +60,7 @@ class StreamFrameWriter : public FrameWriter { public: ~StreamFrameWriter() override = default; - void addFrame(std::string &&frame_data) override; + void addFrame(QByteArrayView frame_data) override; }; /// wrapper class for QTcpSocket and QWebSocket diff --git a/libshviotqt/src/rpc/serialportsocket.cpp b/libshviotqt/src/rpc/serialportsocket.cpp index 2b4ad2c20..42032ff96 100644 --- a/libshviotqt/src/rpc/serialportsocket.cpp +++ b/libshviotqt/src/rpc/serialportsocket.cpp @@ -136,7 +136,7 @@ void SerialFrameReader::finishFrame() return; } } - auto protocol = static_cast(shv::chainpack::Rpc::ProtocolType::ChainPack); + auto protocol = static_cast(shv::chainpack::Rpc::ProtocolType::ChainPack); if (m_readBuffer.empty() || m_readBuffer[0] != protocol) { logSerialPortSocketD() << "Protocol type Error"; setState(ReadState::WaitingForStx); @@ -149,7 +149,7 @@ void SerialFrameReader::finishFrame() //====================================================== // SerialFrameWriter //====================================================== -void SerialFrameWriter::addFrame(std::string &&frame_data) +void SerialFrameWriter::addFrame(QByteArrayView frame_data) { QByteArray data_to_write; auto write_escaped = [&data_to_write](uint8_t b) { diff --git a/libshviotqt/src/rpc/socket.cpp b/libshviotqt/src/rpc/socket.cpp index 306e31324..3dcf99c18 100644 --- a/libshviotqt/src/rpc/socket.cpp +++ b/libshviotqt/src/rpc/socket.cpp @@ -86,7 +86,7 @@ void StreamFrameReader::addData(std::string_view data) //====================================================== // StreamFrameWriter //====================================================== -void StreamFrameWriter::addFrame(std::string &&frame_data) +void StreamFrameWriter::addFrame(QByteArrayView frame_data) { using namespace shv::chainpack; std::ostringstream out; From 1acddf0914b3f3c02bc97de6ca9e9be9525da7dc Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 29 Jan 2024 19:17:47 +0100 Subject: [PATCH 11/17] Clang tidy warning fixed --- examples/cli/shvdevice/src/application.cpp | 2 +- .../include/shv/chainpack/rpcdriver.h | 2 +- .../include/shv/chainpack/socketrpcdriver.h | 2 +- libshvchainpack/src/chainpack/rpcdriver.cpp | 4 ++-- .../src/chainpack/socketrpcdriver.cpp | 2 +- .../include/shv/iotqt/rpc/clientconnection.h | 1 + .../include/shv/iotqt/rpc/localsocket.h | 2 +- .../include/shv/iotqt/rpc/serialportsocket.h | 12 +++++++----- libshviotqt/include/shv/iotqt/rpc/socket.h | 18 +++++++++++------- .../shv/iotqt/rpc/socketrpcconnection.h | 2 +- libshviotqt/include/shv/iotqt/rpc/websocket.h | 2 +- libshviotqt/src/rpc/localsocket.cpp | 5 +++-- libshviotqt/src/rpc/serialportsocket.cpp | 6 +++--- libshviotqt/src/rpc/socket.cpp | 8 ++++---- libshviotqt/src/rpc/socketrpcconnection.cpp | 4 ++-- libshviotqt/src/rpc/websocket.cpp | 4 ++-- 16 files changed, 42 insertions(+), 34 deletions(-) diff --git a/examples/cli/shvdevice/src/application.cpp b/examples/cli/shvdevice/src/application.cpp index 36811f22f..fbf6e9fb3 100644 --- a/examples/cli/shvdevice/src/application.cpp +++ b/examples/cli/shvdevice/src/application.cpp @@ -87,7 +87,7 @@ Application::Application(int &argc, char **argv, AppCliOptions* cli_opts) auto root = new AppRootNode(); m_shvTree = new si::node::ShvNodeTree(root, this); - connect(m_shvTree->root(), &si::node::ShvRootNode::sendRpcMessage, m_rpcConnection, &si::rpc::ClientConnection::sendMessage); + connect(m_shvTree->root(), &si::node::ShvRootNode::sendRpcMessage, m_rpcConnection, &si::rpc::ClientConnection::sendRpcMessage); //m_shvTree->mkdir("sys/rproc"); QTimer::singleShot(0, m_rpcConnection, &si::rpc::ClientConnection::open); diff --git a/libshvchainpack/include/shv/chainpack/rpcdriver.h b/libshvchainpack/include/shv/chainpack/rpcdriver.h index e5c862eb2..026c9ea32 100644 --- a/libshvchainpack/include/shv/chainpack/rpcdriver.h +++ b/libshvchainpack/include/shv/chainpack/rpcdriver.h @@ -29,7 +29,7 @@ class SHVCHAINPACK_DECL_EXPORT RpcDriver protected: virtual bool isOpen() = 0; - virtual void writeFrameData(std::string &&frame_data) = 0; + virtual void writeFrameData(const std::string &frame_data) = 0; /// call it when new data arrived virtual void onFrameDataRead(std::string &&frame_data); diff --git a/libshvchainpack/include/shv/chainpack/socketrpcdriver.h b/libshvchainpack/include/shv/chainpack/socketrpcdriver.h index 86fbd2881..4d674f331 100644 --- a/libshvchainpack/include/shv/chainpack/socketrpcdriver.h +++ b/libshvchainpack/include/shv/chainpack/socketrpcdriver.h @@ -21,7 +21,7 @@ class SHVCHAINPACK_DECL_EXPORT SocketRpcDriver : public RpcDriver void sendNotify(std::string &&method, const RpcValue &result); protected: bool isOpen() override; - void writeFrameData(std::string &&frame_data) override; + void writeFrameData(const std::string &frame_data) override; virtual void idleTaskOnSelectTimeout(); private: diff --git a/libshvchainpack/src/chainpack/rpcdriver.cpp b/libshvchainpack/src/chainpack/rpcdriver.cpp index 1ef9c7182..ebbe6cd3e 100644 --- a/libshvchainpack/src/chainpack/rpcdriver.cpp +++ b/libshvchainpack/src/chainpack/rpcdriver.cpp @@ -31,7 +31,7 @@ void RpcDriver::sendRpcMessage(const RpcMessage &msg) logRpcRawMsg() << SND_LOG_ARROW << msg.toPrettyString(); auto frame_data = msg.toChainPack(); logRpcData() << "SEND data:" << Utils::toHex(frame_data, 0, 250); - writeFrameData(std::move(frame_data)); + writeFrameData(frame_data); } void RpcDriver::sendRpcFrame(RpcFrame &&frame) @@ -42,7 +42,7 @@ void RpcDriver::sendRpcFrame(RpcFrame &&frame) << Utils::toHex(frame.data, 0, 250); auto frame_data = frame.toChainPack(); logRpcData() << "SEND data:" << Utils::toHex(frame_data, 0, 250); - writeFrameData(std::move(frame_data)); + writeFrameData(frame_data); } void RpcDriver::onFrameDataRead(std::string &&frame_data) diff --git a/libshvchainpack/src/chainpack/socketrpcdriver.cpp b/libshvchainpack/src/chainpack/socketrpcdriver.cpp index 7cbdf0f92..212169004 100644 --- a/libshvchainpack/src/chainpack/socketrpcdriver.cpp +++ b/libshvchainpack/src/chainpack/socketrpcdriver.cpp @@ -53,7 +53,7 @@ void SocketRpcDriver::idleTaskOnSelectTimeout() { } -void SocketRpcDriver::writeFrameData(std::string &&frame_data) +void SocketRpcDriver::writeFrameData(const std::string &frame_data) { if(!isOpen()) { nInfo() << "Write to closed socket"; diff --git a/libshviotqt/include/shv/iotqt/rpc/clientconnection.h b/libshviotqt/include/shv/iotqt/rpc/clientconnection.h index 86d392b4f..e7ad5d1a8 100644 --- a/libshviotqt/include/shv/iotqt/rpc/clientconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/clientconnection.h @@ -73,6 +73,7 @@ class SHVIOTQT_DECL_EXPORT ClientConnection : public SocketRpcConnection protected: bool isShvPathMutedInLog(const std::string &shv_path, const std::string &method) const; public: + [[deprecated]] void sendMessage(const shv::chainpack::RpcMessage &rpc_msg) { sendRpcMessage(rpc_msg); } /// IRpcConnection interface implementation void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) override; void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) override; diff --git a/libshviotqt/include/shv/iotqt/rpc/localsocket.h b/libshviotqt/include/shv/iotqt/rpc/localsocket.h index 32927ceec..4ed38bfaa 100644 --- a/libshviotqt/include/shv/iotqt/rpc/localsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/localsocket.h @@ -18,7 +18,7 @@ class SHVIOTQT_DECL_EXPORT LocalSocket : public Socket ~LocalSocket() override; std::string readFrameData() override; - void writeFrameData(std::string &&frame_data) override; + void writeFrameData(const std::string &frame_data) override; void connectToHost(const QUrl &url) override; void close() override; diff --git a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h index 5b1cb271c..87dd4a598 100644 --- a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h @@ -11,7 +11,8 @@ class QTimer; namespace shv::iotqt::rpc { -class SerialFrameReader : public FrameReader { +class SerialFrameReader : public FrameReader +{ public: enum class ReadState {WaitingForStx, WaitingForEtx, WaitingForCrc}; public: @@ -32,12 +33,13 @@ class SerialFrameReader : public FrameReader { bool m_withCrcCheck = true; }; -class SerialFrameWriter : public FrameWriter { +class SerialFrameWriter : public FrameWriter +{ public: ~SerialFrameWriter() override = default; - void addFrame(QByteArrayView frame_data) override; -public: + void addFrame(const std::string &frame_data) override; +private: bool m_withCrcCheck = true; }; @@ -50,7 +52,7 @@ class SHVIOTQT_DECL_EXPORT SerialPortSocket : public Socket SerialPortSocket(QSerialPort *port, QObject *parent = nullptr); std::string readFrameData() override; - void writeFrameData(std::string &&frame_data) override; + void writeFrameData(const std::string &frame_data) override; void setReceiveTimeout(int millis); diff --git a/libshviotqt/include/shv/iotqt/rpc/socket.h b/libshviotqt/include/shv/iotqt/rpc/socket.h index cb4d6fb73..24b839db8 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socket.h +++ b/libshviotqt/include/shv/iotqt/rpc/socket.h @@ -10,6 +10,7 @@ #include class QTcpSocket; + #ifdef WITH_SHV_WEBSOCKETS class QWebSocket; #endif @@ -35,10 +36,11 @@ class FrameReader { std::deque m_frames; }; -class FrameWriter { +class FrameWriter +{ public: virtual ~FrameWriter() = default; - virtual void addFrame(QByteArrayView frame_data) = 0; + virtual void addFrame(const std::string &frame_data) = 0; void flushToDevice(QIODevice *device); #ifdef WITH_SHV_WEBSOCKETS void flushToWebSocket(QWebSocket *socket); @@ -47,7 +49,8 @@ class FrameWriter { QList m_messageDataToWrite; }; -class StreamFrameReader : public FrameReader { +class StreamFrameReader : public FrameReader +{ public: ~StreamFrameReader() override = default; @@ -56,11 +59,12 @@ class StreamFrameReader : public FrameReader { std::string m_readBuffer; }; -class StreamFrameWriter : public FrameWriter { +class StreamFrameWriter : public FrameWriter +{ public: ~StreamFrameWriter() override = default; - void addFrame(QByteArrayView frame_data) override; + void addFrame(const std::string &frame_data) override; }; /// wrapper class for QTcpSocket and QWebSocket @@ -88,7 +92,7 @@ class SHVIOTQT_DECL_EXPORT Socket : public QObject virtual quint16 peerPort() const = 0; virtual std::string readFrameData() = 0; - virtual void writeFrameData(std::string &&frame_data) = 0; + virtual void writeFrameData(const std::string &frame_data) = 0; virtual void ignoreSslErrors() = 0; @@ -115,7 +119,7 @@ class SHVIOTQT_DECL_EXPORT TcpSocket : public Socket TcpSocket(QTcpSocket *socket, QObject *parent = nullptr); std::string readFrameData() override; - void writeFrameData(std::string &&frame_data) override; + void writeFrameData(const std::string &frame_data) override; void connectToHost(const QUrl &url) override; void close() override; diff --git a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h index 6782b93b8..e0157dec6 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h +++ b/libshviotqt/include/shv/iotqt/rpc/socketrpcconnection.h @@ -45,7 +45,7 @@ class SHVIOTQT_DECL_EXPORT SocketRpcConnection : public QObject, public shv::cha protected: // RpcDriver interface bool isOpen() Q_DECL_OVERRIDE; - void writeFrameData(std::string &&frame_data) override; + void writeFrameData(const std::string &frame_data) override; Socket* socket(); void onReadyRead(); diff --git a/libshviotqt/include/shv/iotqt/rpc/websocket.h b/libshviotqt/include/shv/iotqt/rpc/websocket.h index f48507a31..5fa7dd78a 100644 --- a/libshviotqt/include/shv/iotqt/rpc/websocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/websocket.h @@ -16,7 +16,7 @@ class SHVIOTQT_DECL_EXPORT WebSocket : public Socket WebSocket(QWebSocket *socket, QObject *parent = nullptr); std::string readFrameData() override; - void writeFrameData(std::string &&frame_data) override; + void writeFrameData(const std::string &frame_data) override; void connectToHost(const QUrl &url) override; void close() override; diff --git a/libshviotqt/src/rpc/localsocket.cpp b/libshviotqt/src/rpc/localsocket.cpp index fed59d4a9..29498156e 100644 --- a/libshviotqt/src/rpc/localsocket.cpp +++ b/libshviotqt/src/rpc/localsocket.cpp @@ -3,6 +3,7 @@ #include #include +#include #include namespace shv::iotqt::rpc { @@ -98,9 +99,9 @@ std::string LocalSocket::readFrameData() return m_frameReader->getFrame(); } -void LocalSocket::writeFrameData(std::string &&frame_data) +void LocalSocket::writeFrameData(const std::string &frame_data) { - m_frameWriter->addFrame(std::move(frame_data)); + m_frameWriter->addFrame(frame_data); flushWriteBuffer(); } diff --git a/libshviotqt/src/rpc/serialportsocket.cpp b/libshviotqt/src/rpc/serialportsocket.cpp index 42032ff96..767b0ace0 100644 --- a/libshviotqt/src/rpc/serialportsocket.cpp +++ b/libshviotqt/src/rpc/serialportsocket.cpp @@ -149,7 +149,7 @@ void SerialFrameReader::finishFrame() //====================================================== // SerialFrameWriter //====================================================== -void SerialFrameWriter::addFrame(QByteArrayView frame_data) +void SerialFrameWriter::addFrame(const std::string &frame_data) { QByteArray data_to_write; auto write_escaped = [&data_to_write](uint8_t b) { @@ -318,9 +318,9 @@ std::string SerialPortSocket::readFrameData() return m_frameReader.getFrame(); } -void SerialPortSocket::writeFrameData(std::string &&frame_data) +void SerialPortSocket::writeFrameData(const std::string &frame_data) { - m_frameWriter.addFrame(std::move(frame_data)); + m_frameWriter.addFrame(frame_data); flushWriteBuffer(); } diff --git a/libshviotqt/src/rpc/socket.cpp b/libshviotqt/src/rpc/socket.cpp index 3dcf99c18..99dede461 100644 --- a/libshviotqt/src/rpc/socket.cpp +++ b/libshviotqt/src/rpc/socket.cpp @@ -86,7 +86,7 @@ void StreamFrameReader::addData(std::string_view data) //====================================================== // StreamFrameWriter //====================================================== -void StreamFrameWriter::addFrame(QByteArrayView frame_data) +void StreamFrameWriter::addFrame(const std::string &frame_data) { using namespace shv::chainpack; std::ostringstream out; @@ -97,7 +97,7 @@ void StreamFrameWriter::addFrame(QByteArrayView frame_data) auto len_data = out.str(); QByteArray data(len_data.data(), len_data.size()); data += static_cast(Rpc::ProtocolType::ChainPack); - data.append(frame_data); + data.append(frame_data.data(), frame_data.size()); m_messageDataToWrite.append(data); } @@ -205,9 +205,9 @@ std::string TcpSocket::readFrameData() return m_frameReader.getFrame(); } -void TcpSocket::writeFrameData(std::string &&frame_data) +void TcpSocket::writeFrameData(const std::string &frame_data) { - m_frameWriter.addFrame(std::move(frame_data)); + m_frameWriter.addFrame(frame_data); flushWriteBuffer(); } diff --git a/libshviotqt/src/rpc/socketrpcconnection.cpp b/libshviotqt/src/rpc/socketrpcconnection.cpp index 622b1e891..15293510c 100644 --- a/libshviotqt/src/rpc/socketrpcconnection.cpp +++ b/libshviotqt/src/rpc/socketrpcconnection.cpp @@ -121,9 +121,9 @@ bool SocketRpcConnection::isOpen() return isSocketConnected(); } -void SocketRpcConnection::writeFrameData(std::string &&frame_data) +void SocketRpcConnection::writeFrameData(const std::string &frame_data) { - socket()->writeFrameData(std::move(frame_data)); + socket()->writeFrameData(frame_data); } void SocketRpcConnection::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) diff --git a/libshviotqt/src/rpc/websocket.cpp b/libshviotqt/src/rpc/websocket.cpp index fd88983df..37c2e22e4 100644 --- a/libshviotqt/src/rpc/websocket.cpp +++ b/libshviotqt/src/rpc/websocket.cpp @@ -70,9 +70,9 @@ std::string WebSocket::readFrameData() return m_frameReader.getFrame(); } -void WebSocket::writeFrameData(std::string &&frame_data) +void WebSocket::writeFrameData(const std::string &frame_data) { - m_frameWriter.addFrame(std::move(frame_data)); + m_frameWriter.addFrame(frame_data); flushWriteBuffer(); } From de92755e85200fcac8655241702f8a39e7575293 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 29 Jan 2024 22:42:05 +0100 Subject: [PATCH 12/17] Unix socket with serial protocol CRC check removed, reset communication impl --- .../include/shv/iotqt/rpc/localsocket.h | 3 ++ .../include/shv/iotqt/rpc/serialportsocket.h | 8 ++++- libshviotqt/include/shv/iotqt/rpc/socket.h | 4 ++- libshviotqt/src/rpc/clientconnection.cpp | 1 + libshviotqt/src/rpc/localsocket.cpp | 10 ++++-- libshviotqt/src/rpc/serialportsocket.cpp | 32 ++++++++++++++++--- libshviotqt/src/rpc/socket.cpp | 6 ++-- 7 files changed, 54 insertions(+), 10 deletions(-) diff --git a/libshviotqt/include/shv/iotqt/rpc/localsocket.h b/libshviotqt/include/shv/iotqt/rpc/localsocket.h index 4ed38bfaa..746a43d40 100644 --- a/libshviotqt/include/shv/iotqt/rpc/localsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/localsocket.h @@ -23,6 +23,9 @@ class SHVIOTQT_DECL_EXPORT LocalSocket : public Socket void connectToHost(const QUrl &url) override; void close() override; void abort() override; + + void resetCommunication() override; + QAbstractSocket::SocketState state() const override; QString errorString() const override; QHostAddress peerAddress() const override; diff --git a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h index 87dd4a598..32e2c56cf 100644 --- a/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h +++ b/libshviotqt/include/shv/iotqt/rpc/serialportsocket.h @@ -15,7 +15,9 @@ class SerialFrameReader : public FrameReader { public: enum class ReadState {WaitingForStx, WaitingForEtx, WaitingForCrc}; + enum class CrcCheck {No, Yes}; public: + SerialFrameReader(CrcCheck crc); ~SerialFrameReader() override = default; void addData(std::string_view data) override; @@ -36,9 +38,13 @@ class SerialFrameReader : public FrameReader class SerialFrameWriter : public FrameWriter { public: + enum class CrcCheck {No, Yes}; +public: + SerialFrameWriter(CrcCheck crc); ~SerialFrameWriter() override = default; void addFrame(const std::string &frame_data) override; + void resetCommunication() override; private: bool m_withCrcCheck = true; }; @@ -59,7 +65,7 @@ class SHVIOTQT_DECL_EXPORT SerialPortSocket : public Socket void connectToHost(const QUrl &url) override; void close() override; void abort() override; - void reset(); + void resetCommunication() override; QAbstractSocket::SocketState state() const override; QString errorString() const override; QHostAddress peerAddress() const override; diff --git a/libshviotqt/include/shv/iotqt/rpc/socket.h b/libshviotqt/include/shv/iotqt/rpc/socket.h index 24b839db8..8a2f4abb1 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socket.h +++ b/libshviotqt/include/shv/iotqt/rpc/socket.h @@ -41,6 +41,7 @@ class FrameWriter public: virtual ~FrameWriter() = default; virtual void addFrame(const std::string &frame_data) = 0; + virtual void resetCommunication() {} void flushToDevice(QIODevice *device); #ifdef WITH_SHV_WEBSOCKETS void flushToWebSocket(QWebSocket *socket); @@ -84,6 +85,7 @@ class SHVIOTQT_DECL_EXPORT Socket : public QObject virtual void close() = 0; virtual void abort() = 0; + virtual void resetCommunication() {} virtual QAbstractSocket::SocketState state() const = 0; virtual QString errorString() const = 0; @@ -103,7 +105,7 @@ class SHVIOTQT_DECL_EXPORT Socket : public QObject Q_SIGNAL void readyRead(); //Q_SIGNAL void bytesWritten(qint64 bytes); - Q_SIGNAL void socketReset(); + //Q_SIGNAL void socketReset(); Q_SIGNAL void stateChanged(QAbstractSocket::SocketState state); Q_SIGNAL void error(QAbstractSocket::SocketError socket_error); diff --git a/libshviotqt/src/rpc/clientconnection.cpp b/libshviotqt/src/rpc/clientconnection.cpp index 0306f1c67..c16ecdf6a 100644 --- a/libshviotqt/src/rpc/clientconnection.cpp +++ b/libshviotqt/src/rpc/clientconnection.cpp @@ -426,6 +426,7 @@ void ClientConnection::onSocketConnectedChanged(bool is_connected) shvInfo() << objectName() << "connection id:" << connectionId() << "Socket connected to RPC server"; shvInfo() << "peer:" << peerAddress() << "port:" << peerPort(); setState(State::SocketConnected); + socket()->resetCommunication(); if(loginType() == LoginType::None) { shvInfo() << "Connection scheme:" << connectionUrl().scheme() << " is skipping login phase."; setState(State::BrokerConnected); diff --git a/libshviotqt/src/rpc/localsocket.cpp b/libshviotqt/src/rpc/localsocket.cpp index 29498156e..98ff419d6 100644 --- a/libshviotqt/src/rpc/localsocket.cpp +++ b/libshviotqt/src/rpc/localsocket.cpp @@ -31,8 +31,8 @@ LocalSocket::LocalSocket(QLocalSocket *socket, Protocol protocol, QObject *paren , m_socket(socket) { if (protocol == Protocol::Serial) { - m_frameReader = new SerialFrameReader(); - m_frameWriter = new SerialFrameWriter(); + m_frameReader = new SerialFrameReader(SerialFrameReader::CrcCheck::No); + m_frameWriter = new SerialFrameWriter(SerialFrameWriter::CrcCheck::No); } else { m_frameReader = new StreamFrameReader(); @@ -120,6 +120,12 @@ void LocalSocket::abort() m_socket->abort(); } +void LocalSocket::resetCommunication() +{ + m_frameWriter->resetCommunication(); + flushWriteBuffer(); +} + QAbstractSocket::SocketState LocalSocket::state() const { return LocalSocket_convertState(m_socket->state()); diff --git a/libshviotqt/src/rpc/serialportsocket.cpp b/libshviotqt/src/rpc/serialportsocket.cpp index 767b0ace0..5462b946b 100644 --- a/libshviotqt/src/rpc/serialportsocket.cpp +++ b/libshviotqt/src/rpc/serialportsocket.cpp @@ -30,8 +30,15 @@ enum EscCodes: uint8_t { EESC = 0x0A, }; +SerialFrameReader::SerialFrameReader(CrcCheck crc) + : m_withCrcCheck(crc == CrcCheck::Yes) +{ + +} + void SerialFrameReader::addData(std::string_view data) { + shvDebug() << "===> received:" << data.size() << "bytes:" << chainpack::utils::hexArray(data.data(), data.size()); auto add_byte = [this](string &buff, uint8_t b) { if (inEscape()) { switch (b) { @@ -142,6 +149,7 @@ void SerialFrameReader::finishFrame() setState(ReadState::WaitingForStx); return; } + shvDebug() << "ADD FRAME:" << chainpack::utils::hexArray(m_readBuffer.data(), m_readBuffer.size()); m_frames.emplace_back(m_readBuffer.data(), m_readBuffer.size()); setState(ReadState::WaitingForStx); } @@ -149,6 +157,11 @@ void SerialFrameReader::finishFrame() //====================================================== // SerialFrameWriter //====================================================== +SerialFrameWriter::SerialFrameWriter(CrcCheck crc) + : m_withCrcCheck(crc == CrcCheck::Yes) +{ +} + void SerialFrameWriter::addFrame(const std::string &frame_data) { QByteArray data_to_write; @@ -179,12 +192,23 @@ void SerialFrameWriter::addFrame(const std::string &frame_data) m_messageDataToWrite << data_to_write; } +void SerialFrameWriter::resetCommunication() +{ + QByteArray ba; + ba.append(static_cast(STX)); + ba.append(static_cast(ETX)); + ba.append('\0'); + m_messageDataToWrite << ba; +} + //====================================================== // SerialPortSocket //====================================================== SerialPortSocket::SerialPortSocket(QSerialPort *port, QObject *parent) : Super(parent) , m_port(port) + , m_frameReader(SerialFrameReader::CrcCheck::Yes) + , m_frameWriter(SerialFrameWriter::CrcCheck::Yes) { m_port->setParent(this); @@ -247,7 +271,7 @@ void SerialPortSocket::setReceiveTimeout(int millis) m_readDataTimeout->setSingleShot(true); connect(m_readDataTimeout, &QTimer::timeout, this, [this]() { if(m_frameReader.readState() != SerialFrameReader::ReadState::WaitingForStx) { - reset(); + resetCommunication(); } }); } @@ -263,7 +287,7 @@ void SerialPortSocket::connectToHost(const QUrl &url) shvInfo() << "opening serial port:" << m_port->portName(); if(m_port->open(QIODevice::ReadWrite)) { shvInfo() << "Ok"; - reset(); + resetCommunication(); setState(QAbstractSocket::ConnectedState); } else { @@ -286,9 +310,9 @@ void SerialPortSocket::abort() close(); } -void SerialPortSocket::reset() +void SerialPortSocket::resetCommunication() { - //TODO: reset will be implemented when it will be finished in documentation + m_frameWriter.resetCommunication(); } QAbstractSocket::SocketState SerialPortSocket::state() const diff --git a/libshviotqt/src/rpc/socket.cpp b/libshviotqt/src/rpc/socket.cpp index 99dede461..734d1c058 100644 --- a/libshviotqt/src/rpc/socket.cpp +++ b/libshviotqt/src/rpc/socket.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,7 @@ void FrameWriter::flushToDevice(QIODevice *device) while (!m_messageDataToWrite.isEmpty()) { auto data = m_messageDataToWrite[0]; auto n = device->write(data); + shvDebug() << "<=== sending:" << data.size() << "bytes:" << chainpack::utils::hexArray(data.constData(), data.size()); if (n <= 0) { shvWarning() << "Write data error."; break; @@ -218,8 +220,8 @@ void TcpSocket::ignoreSslErrors() void TcpSocket::onDataReadyRead() { auto ba = m_socket->readAll(); - std::string_view escaped_data(ba.constData(), ba.size()); - m_frameReader.addData(escaped_data); + std::string_view data(ba.constData(), ba.size()); + m_frameReader.addData(data); if (!m_frameReader.isEmpty()) { emit readyRead(); } From 4767cd75fe9e27559db3948c0c5e917abebea398 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 29 Jan 2024 22:45:43 +0100 Subject: [PATCH 13/17] Fixed bug, when only first frame of frames received was processed. --- libshviotqt/src/rpc/socketrpcconnection.cpp | 24 ++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/libshviotqt/src/rpc/socketrpcconnection.cpp b/libshviotqt/src/rpc/socketrpcconnection.cpp index 15293510c..9b04811c4 100644 --- a/libshviotqt/src/rpc/socketrpcconnection.cpp +++ b/libshviotqt/src/rpc/socketrpcconnection.cpp @@ -55,7 +55,6 @@ void SocketRpcConnection::setSocket(Socket *socket) }); bool is_test_run = QCoreApplication::instance() == nullptr; connect(socket, &Socket::readyRead, this, &SocketRpcConnection::onReadyRead, is_test_run? Qt::AutoConnection: Qt::QueuedConnection); - connect(socket, &Socket::readyRead, this, &SocketRpcConnection::socketDataReadyRead, is_test_run? Qt::AutoConnection: Qt::QueuedConnection); connect(socket, &Socket::connected, this, [this]() { shvDebug() << this << "Socket connected!!!"; emit socketConnectedChanged(true); @@ -99,15 +98,20 @@ void SocketRpcConnection::connectToHost(const QUrl &url) void SocketRpcConnection::onReadyRead() { - auto frame_data = socket()->readFrameData(); -#ifdef DUMP_DATA_FILE - QFile *f = findChild("DUMP_DATA_FILE"); - if(f) { - f->write(ba.constData(), ba.length()); - f->flush(); - } -#endif - onFrameDataRead(std::move(frame_data)); + while (true) { + auto frame_data = socket()->readFrameData(); + if (frame_data.empty()) + break; + #ifdef DUMP_DATA_FILE + QFile *f = findChild("DUMP_DATA_FILE"); + if(f) { + f->write(ba.constData(), ba.length()); + f->flush(); + } + #endif + onFrameDataRead(std::move(frame_data)); + }; + emit socketDataReadyRead(); } void SocketRpcConnection::onParseDataException(const chainpack::ParseException &e) From e33e0cad624c781f9b4174118cbcefa5bae61e45 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Tue, 30 Jan 2024 15:38:47 +0100 Subject: [PATCH 14/17] RpcValue::metaStripped() removed, some comments deleted --- .../include/shv/chainpack/rpcmessage.h | 6 ----- .../include/shv/chainpack/rpcvalue.h | 3 +-- libshvchainpack/src/chainpack/datachange.cpp | 3 ++- libshvchainpack/src/chainpack/rpcmessage.cpp | 24 +------------------ libshvchainpack/src/chainpack/rpcvalue.cpp | 9 +------ libshvchainpack/tests/test_rpcvalue.cpp | 9 ++++--- libshviotqt/include/shv/iotqt/rpc/socket.h | 3 --- .../test_serialportsocket.cpp | 6 ----- 8 files changed, 9 insertions(+), 54 deletions(-) diff --git a/libshvchainpack/include/shv/chainpack/rpcmessage.h b/libshvchainpack/include/shv/chainpack/rpcmessage.h index 8228f4fbc..3bae403d4 100644 --- a/libshvchainpack/include/shv/chainpack/rpcmessage.h +++ b/libshvchainpack/include/shv/chainpack/rpcmessage.h @@ -41,7 +41,6 @@ class SHVCHAINPACK_DECL_EXPORT RpcMessage ShvPath = 9, // 9 Method = 10, // 10 CallerIds = 11, // 11 - //ProtocolType, //needed when dest client is using different version than source one to translate raw message data to correct format RevCallerIds = 13, AccessGrant = 14, TunnelCtl = 15, @@ -126,11 +125,6 @@ class SHVCHAINPACK_DECL_EXPORT RpcMessage static RpcValue userId(RpcValue::MetaData &meta); static void setUserId(RpcValue::MetaData &meta, const RpcValue &user_id); - //static Rpc::ProtocolType protocolType(const RpcValue::MetaData &meta); - //static void setProtocolType(RpcValue::MetaData &meta, shv::chainpack::Rpc::ProtocolType ver); - //Rpc::ProtocolType protocolType() const; - //void setProtocolType(shv::chainpack::Rpc::ProtocolType ver); - std::string toPrettyString() const; std::string toCpon() const; std::string toChainPack() const; diff --git a/libshvchainpack/include/shv/chainpack/rpcvalue.h b/libshvchainpack/include/shv/chainpack/rpcvalue.h index 881920b81..bbf1f7226 100644 --- a/libshvchainpack/include/shv/chainpack/rpcvalue.h +++ b/libshvchainpack/include/shv/chainpack/rpcvalue.h @@ -410,8 +410,7 @@ class SHVCHAINPACK_DECL_EXPORT RpcValue void set(const RpcValue::String &key, const RpcValue &val); void append(const RpcValue &val); - RpcValue metaStripped() const; - MetaData stripMeta(); + MetaData takeMeta(); std::string toPrettyString(const std::string &indent = std::string()) const; std::string toStdString() const; diff --git a/libshvchainpack/src/chainpack/datachange.cpp b/libshvchainpack/src/chainpack/datachange.cpp index ed53a2f0a..871d02aa2 100644 --- a/libshvchainpack/src/chainpack/datachange.cpp +++ b/libshvchainpack/src/chainpack/datachange.cpp @@ -106,7 +106,8 @@ DataChange DataChange::fromRpcValue(const RpcValue &val) } } { - RpcValue raw_val = val.metaStripped(); + auto raw_val = val; + raw_val.takeMeta(); ret.setValue(raw_val); } set_meta_data: diff --git a/libshvchainpack/src/chainpack/rpcmessage.cpp b/libshvchainpack/src/chainpack/rpcmessage.cpp index 84ebe5b55..5003c7cec 100644 --- a/libshvchainpack/src/chainpack/rpcmessage.cpp +++ b/libshvchainpack/src/chainpack/rpcmessage.cpp @@ -26,7 +26,6 @@ RpcMessage::MetaType::MetaType() {static_cast(Tag::ShvPath), {static_cast(Tag::ShvPath), Rpc::PAR_PATH}}, {static_cast(Tag::Method), {static_cast(Tag::Method), Rpc::PAR_METHOD}}, {static_cast(Tag::CallerIds), {static_cast(Tag::CallerIds), "cid"}}, - //{static_cast(Tag::ProtocolType), {static_cast(Tag::ProtocolType), "protocol"}}, {static_cast(Tag::RevCallerIds), {static_cast(Tag::RevCallerIds), "rcid"}}, {static_cast(Tag::AccessGrant), {static_cast(Tag::AccessGrant), "grant"}}, {static_cast(Tag::TunnelCtl), {static_cast(Tag::TunnelCtl), "tctl"}}, @@ -471,27 +470,7 @@ void RpcMessage::setUserId(RpcValue::MetaData &meta, const RpcValue &user_id) { meta.setValue(RpcMessage::MetaType::Tag::UserId, user_id); } -/* -Rpc::ProtocolType RpcMessage::protocolType(const RpcValue::MetaData &meta) -{ - return static_cast(meta.value(RpcMessage::MetaType::Tag::ProtocolType).toUInt()); -} - -void RpcMessage::setProtocolType(RpcValue::MetaData &meta, Rpc::ProtocolType ver) -{ - meta.setValue(RpcMessage::MetaType::Tag::ProtocolType, ver == Rpc::ProtocolType::Invalid? RpcValue(): RpcValue(static_cast(ver))); -} -Rpc::ProtocolType RpcMessage::protocolType() const -{ - return static_cast(metaValue(RpcMessage::MetaType::Tag::ProtocolType).toUInt()); -} - -void RpcMessage::setProtocolType(Rpc::ProtocolType ver) -{ - setMetaValue(RpcMessage::MetaType::Tag::ProtocolType, ver == Rpc::ProtocolType::Invalid? RpcValue(): RpcValue(static_cast(ver))); -} -*/ void RpcMessage::write(AbstractStreamWriter &wr) const { assert(m_value.isValid()); @@ -534,7 +513,7 @@ std::string RpcMessage::toChainPack() const RpcFrame RpcMessage::toToRpcFrame() const { auto val = m_value; - auto meta = val.stripMeta(); + auto meta = val.takeMeta(); auto data = val.toChainPack(); return RpcFrame {std::move(meta), std::move(data)}; } @@ -859,5 +838,4 @@ RpcResponse& RpcResponse::setRequestId(const RpcValue &id) return *this; } - } // namespace shv diff --git a/libshvchainpack/src/chainpack/rpcvalue.cpp b/libshvchainpack/src/chainpack/rpcvalue.cpp index 3a3a42e68..40060e67b 100644 --- a/libshvchainpack/src/chainpack/rpcvalue.cpp +++ b/libshvchainpack/src/chainpack/rpcvalue.cpp @@ -728,14 +728,7 @@ void RpcValue::append(const RpcValue &val) m_ptr->append(val); } -RpcValue RpcValue::metaStripped() const -{ - RpcValue ret = *this; - ret.m_ptr->stripMeta(); - return ret; -} - -RpcValue::MetaData RpcValue::stripMeta() +RpcValue::MetaData RpcValue::takeMeta() { return m_ptr->stripMeta(); } diff --git a/libshvchainpack/tests/test_rpcvalue.cpp b/libshvchainpack/tests/test_rpcvalue.cpp index d247b0156..8dc16f501 100644 --- a/libshvchainpack/tests/test_rpcvalue.cpp +++ b/libshvchainpack/tests/test_rpcvalue.cpp @@ -6,8 +6,6 @@ #include -#include - using namespace shv::chainpack; using namespace std; using namespace std::string_literals; @@ -72,13 +70,14 @@ DOCTEST_TEST_CASE("RpcValue") REQUIRE(rpcval.metaValue(2) == RpcValue(42)); REQUIRE(rv1.metaValue(2) == RpcValue(12)); } - DOCTEST_SUBCASE("strip Meta test") + DOCTEST_SUBCASE("take Meta test") { - nDebug() << "================================= stripMeta Test ====================================="; + nDebug() << "================================= takeMeta Test ====================================="; auto rpcval = RpcValue::fromCpon(R"(<1:2,2:12,8:"foo",9:[1,2,3],"bar":"baz",>{"META":17,"18":19})"); auto rv1 = rpcval; auto rv2 = rv1; - auto rv3 = rv1.metaStripped(); + auto rv3 = rv1; + rv3.takeMeta(); REQUIRE(rpcval.refCnt() == 3); REQUIRE(rv3.refCnt() == 1); REQUIRE(rv1.metaData().isEmpty() == false); diff --git a/libshviotqt/include/shv/iotqt/rpc/socket.h b/libshviotqt/include/shv/iotqt/rpc/socket.h index 8a2f4abb1..891e20954 100644 --- a/libshviotqt/include/shv/iotqt/rpc/socket.h +++ b/libshviotqt/include/shv/iotqt/rpc/socket.h @@ -103,9 +103,6 @@ class SHVIOTQT_DECL_EXPORT Socket : public QObject Q_SIGNAL void connected(); Q_SIGNAL void disconnected(); Q_SIGNAL void readyRead(); - //Q_SIGNAL void bytesWritten(qint64 bytes); - - //Q_SIGNAL void socketReset(); Q_SIGNAL void stateChanged(QAbstractSocket::SocketState state); Q_SIGNAL void error(QAbstractSocket::SocketError socket_error); diff --git a/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp b/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp index a987e051e..815af9e2b 100644 --- a/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp +++ b/libshviotqt/tests/serialportsocket/test_serialportsocket.cpp @@ -65,8 +65,6 @@ DOCTEST_TEST_CASE("Send") serial->clearWrittenData(); conn.sendRpcMessage(rq); auto data = serial->writtenData(); - //logSerialPortSocketD() << "msg:" << rq.toCpon(); - //logSerialPortSocketD() << "data:" << utils::hexArray(data.constData(), data.size()); vector rubbish1 = { "", @@ -89,11 +87,7 @@ DOCTEST_TEST_CASE("Send") // add some rubbish auto data2 = data1 + QByteArray::fromStdString(extra_rubbish); rec_msg = {}; - //logSerialPortSocketD().nospace() << "data to send:\n" << utils::hexDump(data2.constData(), data2.size()); serial->setDataToReceive(data2); - //REQUIRE(socket->readMessageError() == SerialPortSocket::ReadMessageError::Ok); - //logSerialPortSocketD() << "rec msg:" << rec_msg.value().toCpon(); - //logSerialPortSocketD() << "rq msg:" << rq.value().toCpon(); REQUIRE(rec_msg.value() == rq.value()); } } From 6a38395061a0b8b77ec6eecd48dd3fa1b0ad430b Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 1 Feb 2024 23:24:45 +0100 Subject: [PATCH 15/17] Utils::hexDump() parameter changed from string to string_view --- libshvchainpack/include/shv/chainpack/utils.h | 2 +- libshvchainpack/src/chainpack/utils.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libshvchainpack/include/shv/chainpack/utils.h b/libshvchainpack/include/shv/chainpack/utils.h index 07edec4dc..08b13ce4b 100644 --- a/libshvchainpack/include/shv/chainpack/utils.h +++ b/libshvchainpack/include/shv/chainpack/utils.h @@ -51,7 +51,7 @@ class SHVCHAINPACK_DECL_EXPORT Utils static std::string toHex(const std::basic_string &bytes); static char fromHex(char c); static std::string fromHex(const std::string &bytes); - static std::string hexDump(const std::string &bytes); + static std::string hexDump(const std::string_view &bytes); template static std::string toString(I n) diff --git a/libshvchainpack/src/chainpack/utils.cpp b/libshvchainpack/src/chainpack/utils.cpp index 8796d6fe8..8d5545cf4 100644 --- a/libshvchainpack/src/chainpack/utils.cpp +++ b/libshvchainpack/src/chainpack/utils.cpp @@ -152,7 +152,7 @@ std::string Utils::fromHex(const std::string &bytes) return ret; } -std::string Utils::hexDump(const std::string &bytes) +std::string Utils::hexDump(const std::string_view &bytes) { return utils::hexDump(bytes.data(), bytes.size()); } From 4b5ac818505d3cc1ddc7f2285c96607536bd8215 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 1 Feb 2024 23:28:36 +0100 Subject: [PATCH 16/17] clang tidy misc-include-cleaner check disabled --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index 3aa430244..192b48ea8 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -55,6 +55,7 @@ Checks: -hicpp-use-override, -hicpp-vararg, -misc-const-correctness, + -misc-include-cleaner, -misc-no-recursion, -misc-non-private-member-variables-in-classes, -misc-unused-parameters, From 8f4da556c5b01bfc0f75051153566791b0d101c3 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 2 Feb 2024 19:32:38 +0100 Subject: [PATCH 17/17] Fixed bug when StreamFrameReader::addData() was running forever. --- libshvchainpack/include/shv/chainpack/utils.h | 2 +- libshvchainpack/src/chainpack/rpcdriver.cpp | 2 +- libshvchainpack/src/chainpack/utils.cpp | 10 +++++----- libshviotqt/src/rpc/socket.cpp | 4 ++++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libshvchainpack/include/shv/chainpack/utils.h b/libshvchainpack/include/shv/chainpack/utils.h index 08b13ce4b..7f55f8346 100644 --- a/libshvchainpack/include/shv/chainpack/utils.h +++ b/libshvchainpack/include/shv/chainpack/utils.h @@ -18,6 +18,7 @@ namespace utils { SHVCHAINPACK_DECL_EXPORT std::string hexArray(const char *bytes, size_t n); SHVCHAINPACK_DECL_EXPORT std::string hexDump(const char *bytes, size_t n); +SHVCHAINPACK_DECL_EXPORT std::string hexDump(const std::string_view &bytes); SHVCHAINPACK_DECL_EXPORT std::string byteToHex( uint8_t i ); SHVCHAINPACK_DECL_EXPORT void byteToHex( std::array &arr, uint8_t i ); @@ -51,7 +52,6 @@ class SHVCHAINPACK_DECL_EXPORT Utils static std::string toHex(const std::basic_string &bytes); static char fromHex(char c); static std::string fromHex(const std::string &bytes); - static std::string hexDump(const std::string_view &bytes); template static std::string toString(I n) diff --git a/libshvchainpack/src/chainpack/rpcdriver.cpp b/libshvchainpack/src/chainpack/rpcdriver.cpp index ebbe6cd3e..dba2f0a27 100644 --- a/libshvchainpack/src/chainpack/rpcdriver.cpp +++ b/libshvchainpack/src/chainpack/rpcdriver.cpp @@ -48,7 +48,7 @@ void RpcDriver::sendRpcFrame(RpcFrame &&frame) void RpcDriver::onFrameDataRead(std::string &&frame_data) { logRpcData() << __PRETTY_FUNCTION__ << "+++++++++++++++++++++++++++++++++"; - logRpcData().nospace() << "FRAME DATA " << frame_data.size() << " bytes of data read:\n" << shv::chainpack::Utils::hexDump(frame_data); + logRpcData().nospace() << "FRAME DATA " << frame_data.size() << " bytes of data read:\n" << shv::chainpack::utils::hexDump(frame_data); try { auto frame = RpcFrame::fromChainPack(std::move(frame_data)); onRpcFrameReceived(std::move(frame)); diff --git a/libshvchainpack/src/chainpack/utils.cpp b/libshvchainpack/src/chainpack/utils.cpp index 8d5545cf4..39bc564e1 100644 --- a/libshvchainpack/src/chainpack/utils.cpp +++ b/libshvchainpack/src/chainpack/utils.cpp @@ -72,6 +72,11 @@ string hexArray(const char *bytes, size_t n) return ret + ']'; } +string hexDump(const std::string_view &bytes) +{ + return utils::hexDump(bytes.data(), bytes.size()); +} + } std::string Utils::removeJsonComments(const std::string &json_str) { @@ -152,11 +157,6 @@ std::string Utils::fromHex(const std::string &bytes) return ret; } -std::string Utils::hexDump(const std::string_view &bytes) -{ - return utils::hexDump(bytes.data(), bytes.size()); -} - RpcValue Utils::mergeMaps(const RpcValue &value_base, const RpcValue &value_over) { if(value_over.isMap() && value_base.isMap()) { diff --git a/libshviotqt/src/rpc/socket.cpp b/libshviotqt/src/rpc/socket.cpp index 734d1c058..6d8538452 100644 --- a/libshviotqt/src/rpc/socket.cpp +++ b/libshviotqt/src/rpc/socket.cpp @@ -61,6 +61,7 @@ void FrameWriter::flushToWebSocket(QWebSocket *socket) void StreamFrameReader::addData(std::string_view data) { m_readBuffer += data; + shvDebug() << "received:\n" << chainpack::utils::hexDump(data); while (true) { std::istringstream in(m_readBuffer); int err_code; @@ -82,6 +83,9 @@ void StreamFrameReader::addData(std::string_view data) m_readBuffer = std::string(m_readBuffer, consumed_len + frame_size); m_frames.push_back(std::move(frame)); } + else { + break; + } } }