/** @file * @author Edouard DUPIN * @copyright 2016, Edouard DUPIN, all right reserved * @license APACHE v2.0 (see license file) */ #include #include #include #include #include #include static const std::string protocolError = "PROTOCOL-ERROR"; appl::clientSpecificInterface::clientSpecificInterface() { m_uid = 0; m_state = appl::clientState::unconnect; APPL_INFO("----------------"); APPL_INFO("-- NEW Client --"); APPL_INFO("----------------"); } appl::clientSpecificInterface::~clientSpecificInterface() { APPL_INFO("-------------------"); APPL_INFO("-- DELETE Client --"); APPL_INFO("-------------------"); } /* void appl::clientSpecificInterface::answerProtocolError(uint32_t _transactionId, const std::string& _errorHelp) { //m_interfaceWeb->answerError(_transactionId, m_routeurUID, ZEUS_ID_SERVICE_ROOT, protocolError, _errorHelp); //m_interfaceWeb->sendCtrl(m_routeurUID, ZEUS_ID_SERVICE_ROOT, "DISCONNECT"); m_state = appl::clientState::disconnect; } */ bool appl::clientSpecificInterface::start(appl::GateWay* _gateway, zeus::WebServer* _interfaceWeb, uint16_t _id) { appl::IOInterface::start(_gateway, _id); m_interfaceWeb = _interfaceWeb; APPL_WARNING("[" << m_uid << "] New client : " << m_clientName); return true; } void appl::clientSpecificInterface::send(ememory::SharedPtr _value) { m_interfaceWeb->writeBinary(_value); } #if 0 void appl::clientSpecificInterface::receive(ememory::SharedPtr _value) { if (_value == nullptr) { return; } //APPL_ERROR(" ==> parse DATA ..."); uint32_t transactionId = _value->getTransactionId(); if (transactionId == 0) { APPL_ERROR("Protocol error ==>missing id"); answerProtocolError(transactionId, "missing parameter: 'id'"); return; } if (_value->getType() == zeus::Message::type::data) { // TRANSMIT DATA ... if (m_state != appl::clientState::clientIdentify) { answerProtocolError(transactionId, "Not identify to send 'data' buffer (multiple packet element)"); return; } uint32_t serviceId = _value->getServiceId(); if (serviceId == 0) { answerProtocolError(transactionId, "Can not send multiple data on the gateway"); return; } serviceId--; if (serviceId >= m_listConnectedService.size()) { m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "NOT-CONNECTED-SERVICE"); return; } if (m_listConnectedService[serviceId] == nullptr) { // TODO ... APPL_ERROR("TODO : Manage this case ..."); return; } m_listConnectedService[serviceId]->m_interfaceClient.callForwardMultiple( m_uid, _value, (uint64_t(m_uid) << 32) + uint64_t(transactionId)); return; } if (_value->getType() != zeus::Message::type::call) { APPL_ERROR("Protocol error ==>missing 'call'"); answerProtocolError(transactionId, "missing parameter: 'call' / wrong type 'call'"); return; } ememory::SharedPtr callObj = ememory::staticPointerCast(_value); std::string callFunction = callObj->getCall(); switch (m_state) { case appl::clientState::disconnect: case appl::clientState::unconnect: { APPL_ERROR("Must never appear"); answerProtocolError(transactionId, "Gateway internal error"); return; } case appl::clientState::connect: { uint32_t serviceId = callObj->getServiceId(); if (serviceId != 0) { APPL_ERROR("Call at a service at this state is not allowed serviceID=" << serviceId); answerProtocolError(transactionId, "MISSING IDENTIFICATION STEP"); return; } m_clientServices.clear(); m_clientgroups.clear(); m_clientName.clear(); if ( callFunction != "identify" && callFunction != "auth" && callFunction != "anonymous") { answerProtocolError(transactionId, "Client must call: identify/auth/anonymous"); return; } if (callFunction == "identify") { std::string clientName = callObj->getParameter(0); std::string clientTocken = callObj->getParameter(1); if (m_userService == nullptr) { answerProtocolError(transactionId, "gateWay internal error 3"); return; } zeus::Future fut = m_userService->m_interfaceClient.call(m_localIdUser, ZEUS_ID_SERVICE_ROOT, "checkTocken", clientName, clientTocken); fut.wait(); // TODO: Set timeout ... if (fut.hasError() == true) { APPL_ERROR("Get error from the service ..."); m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), false); answerProtocolError(transactionId, "connection refused 1"); return; } else if (fut.get() == false) { m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), false); answerProtocolError(transactionId, "connection refused 2"); return; } m_clientName = clientName; } if (callFunction == "auth") { std::string password = callObj->getParameter(0); zeus::Future fut = m_userService->m_interfaceClient.call(m_localIdUser, ZEUS_ID_SERVICE_ROOT, "checkAuth", password); fut.wait(); // TODO: Set timeout ... if (fut.hasError() == true) { APPL_ERROR("Get error from the service ..."); m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), false); answerProtocolError(transactionId, "connection refused 1"); return; } else if (fut.get() == false) { m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), false); answerProtocolError(transactionId, "connection refused 2"); return; } m_clientName = m_userConnectionName; } if (callFunction == "anonymous") { m_clientName = ""; } // -------------------------------- // -- Get groups: // -------------------------------- zeus::Future> futGroup = m_userService->m_interfaceClient.call(m_localIdUser, ZEUS_ID_SERVICE_ROOT, "clientGroupsGet", m_clientName); futGroup.wait(); // TODO: Set timeout ... if (futGroup.hasError() == true) { APPL_ERROR("Get error from the service ..."); m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), false); answerProtocolError(transactionId, "grouping error"); return; } m_clientgroups = futGroup.get(); // -------------------------------- // -- Get services: // -------------------------------- std::vector currentServices = m_gatewayInterface->getAllServiceName(); zeus::Future> futServices = m_userService->m_interfaceClient.call(m_localIdUser, ZEUS_ID_SERVICE_ROOT, "filterClientServices", m_clientName, currentServices); futServices.wait(); // TODO: Set timeout ... if (futServices.hasError() == true) { APPL_ERROR("Get error from the service ..."); m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), false); answerProtocolError(transactionId, "service filtering error"); return; } m_clientServices = futServices.get(); APPL_WARNING("Connection of: '" << m_clientName << "' to '" << m_userConnectionName << "'"); APPL_WARNING(" groups: " << etk::to_string(m_clientgroups)); APPL_WARNING(" services: " << etk::to_string(m_clientServices)); m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), true); m_state = appl::clientState::clientIdentify; return; } break; case appl::clientState::clientIdentify: { uint32_t serviceId = callObj->getServiceId(); if (serviceId == 0) { // This is 2 default service for the cient interface that manage the authorisation of view: if (callFunction == "getServiceCount") { m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), m_clientServices.size()); return; } if (callFunction == "getServiceList") { m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), m_clientServices); //"ServiceManager/v0.1.0" return; } if (callFunction == "link") { // first param: std::string serviceName = callObj->getParameter(0); ZEUS_ERROR("Connect to service : " << serviceName << " " << m_uid); // Check if service already link: auto it = m_listConnectedService.begin(); while (it != m_listConnectedService.end()) { if (*it == nullptr) { ++it; continue; } if ((*it)->getName() != serviceName) { ++it; continue; } break; } if (it == m_listConnectedService.end()) { // check if service is connectable ... if (std::find(m_clientServices.begin(), m_clientServices.end(), serviceName) == m_clientServices.end()) { m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "UN-AUTHORIZED-SERVICE"); return; } ememory::SharedPtr srv = m_gatewayInterface->get(serviceName); if (srv != nullptr) { zeus::Future futLink = srv->m_interfaceClient.call(m_uid, ZEUS_ID_SERVICE_ROOT, "_new", m_userConnectionName, m_clientName, m_clientgroups); futLink.wait(); // TODO: Set timeout ... if (futLink.hasError() == true) { APPL_ERROR("Get error from the service ... LINK"); m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "ERROR-CREATE-SERVICE-INSTANCE"); return; } m_listConnectedService.push_back(srv); ZEUS_ERROR(" ==> get ID : " << m_uid); m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), m_listConnectedService.size()); return; } m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "CAN-NOT-CONNECT-SERVICE"); return; } m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "SERVICE-ALREADY-CONNECTED");; return; } if (callFunction == "unlink") { ZEUS_ERROR("Disconnnect from service : " << m_uid); // first param: the service we want to unconnect ... int64_t localServiceID = callObj->getParameter(0)-1; // Check if service already link: if (localServiceID >= m_listConnectedService.size()) { m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "NOT-CONNECTED-SERVICE"); return; } zeus::Future futUnLink = m_listConnectedService[localServiceID]->m_interfaceClient.call(m_uid, ZEUS_ID_SERVICE_ROOT, "_delete"); futUnLink.wait(); // TODO: Set timeout ... if (futUnLink.hasError() == true) { APPL_ERROR("Get error from the service ... UNLINK"); m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "ERROR-CREATE-SERVICE-INSTANCE"); return; } m_listConnectedService[localServiceID] = nullptr; m_interfaceWeb->answerValue(transactionId, _value->getClientId(), _value->getServiceId(), true); return; } APPL_ERROR("Function does not exist ... '" << callFunction << "'"); m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "CALL-UNEXISTING"); return; } // decrease service ID ... serviceId -= 1; if (serviceId >= m_listConnectedService.size()) { m_interfaceWeb->answerError(transactionId, _value->getClientId(), _value->getServiceId(), "NOT-CONNECTED-SERVICE"); return; } else { if (m_listConnectedService[serviceId] == nullptr) { // TODO ... APPL_ERROR("TODO : Manage this case ..."); return; } auto fut = m_listConnectedService[serviceId]->m_interfaceClient.callForward(m_uid, _value, (uint64_t(m_uid) << 32) + uint64_t(transactionId)); fut.andAll([=](zeus::FutureBase _ret) { ememory::SharedPtr tmpp = _ret.getRaw(); if (tmpp == nullptr) { return true; } APPL_DEBUG(" ==> transmit : " << tmpp->getTransactionId() << " -> " << transactionId); APPL_DEBUG(" msg=" << tmpp); tmpp->setTransactionId(transactionId); tmpp->setClientId(m_routeurUID); tmpp->setServiceId(serviceId+1); APPL_DEBUG("transmit=" << tmpp); m_interfaceWeb->writeBinary(tmpp); // multiple send element ... return tmpp->getPartFinish(); }); } } } } #endif appl::RouterInterface::RouterInterface(const std::string& _ip, uint16_t _port, std::string _userName, appl::GateWay* _gateway) : m_state(appl::clientState::unconnect), m_gateway(_gateway), m_interfaceWeb() { APPL_INFO("----------------------------------------"); APPL_INFO("-- NEW Connection to the ROUTER --"); APPL_INFO("----------------------------------------"); enet::Tcp connection = std::move(enet::connectTcpClient(_ip, _port)); if (connection.getConnectionStatus() != enet::Tcp::status::link) { APPL_ERROR("Can not connect the GateWay-front-end"); return; } m_interfaceWeb.setInterface(std::move(connection), false, _userName); m_interfaceWeb.connect(this, &appl::RouterInterface::onClientData); m_interfaceWeb.connect(true); m_interfaceWeb.setInterfaceName("cli-GW-to-router"); // TODO : Check if user name is accepted ... } appl::RouterInterface::~RouterInterface() { APPL_TODO("Call All unlink ..."); stop(); APPL_INFO("-------------------------------------------"); APPL_INFO("-- DELETE Connection to the ROUTER --"); APPL_INFO("-------------------------------------------"); } void appl::RouterInterface::stop() { /* TODO ... for (auto &it : m_listConnectedService) { if (it == nullptr) { continue; } it->m_interfaceClient.callClient(m_uid, "_delete"); } if (m_userService != nullptr) { m_userService->m_interfaceClient.callClient(m_uid2, "_delete"); m_userService = nullptr; } m_listConnectedService.clear(); */ m_interfaceWeb.disconnect(); } bool appl::RouterInterface::isAlive() { return m_interfaceWeb.isActive(); } void appl::RouterInterface::onClientData(ememory::SharedPtr _value) { if (_value == nullptr) { return; } // Get client ID: uint16_t sourceId = _value->getSourceId(); //APPL_ERROR("[" << clientId << "] get message from front-end gateWay: " << _value); for (auto &it : m_listClients) { if (it->checkId(sourceId) == true) { it->receive(_value); return; } } m_listClients.push_back(ememory::makeShared()); size_t localId = m_listClients.size()-1; bool ret = m_listClients[localId]->start(m_gateway, &m_interfaceWeb, sourceId); if (ret == false) { return; } m_listClients[localId]->receive(_value); } void appl::RouterInterface::send(const ememory::SharedPtr& _data) { m_interfaceWeb.writeBinary(_data); } void appl::RouterInterface::clean() { auto it = m_listClients.begin(); while (it != m_listClients.end()) { if ((*it)->m_state == appl::clientState::disconnect) { it = m_listClients.erase(it); continue; } ++it; } }