[DEV] add support of redirect the client on direct connection of the gateway (if authorised in routeur config file)

This commit is contained in:
Edouard DUPIN 2017-10-14 11:24:45 +02:00
parent 27a7c404fb
commit e7771b706d
7 changed files with 91 additions and 31 deletions

View File

@ -32,28 +32,39 @@ appl::ClientInterface::~ClientInterface() {
APPL_INFO("-------------------"); APPL_INFO("-------------------");
} }
bool appl::ClientInterface::requestURI(const etk::String& _uri) { etk::String appl::ClientInterface::requestURI(const etk::String& _uri, const etk::Map<etk::String,etk::String>& _options) {
APPL_WARNING("request connect on CLIENT: '" << _uri << "'"); APPL_INFO("request connect on CLIENT: '" << _uri << "' from " << m_interfaceClient.getRemoteAddress());
if(m_routerInterface == nullptr) { if(m_routerInterface == nullptr) {
APPL_ERROR("Can not access to the main GateWay interface (nullptr)"); APPL_ERROR("Can not access to the main GateWay interface (nullptr)");
return false; return "CLOSE";
} }
etk::String tmpURI = _uri; etk::String tmpURI = _uri;
if (tmpURI.size() == 0) { if (tmpURI.size() == 0) {
APPL_ERROR("Empty URI ... not supported ..."); APPL_ERROR("Empty URI ... not supported ...");
return false; return "CLOSE";
} }
if (tmpURI[0] == '/') { if (tmpURI[0] == '/') {
tmpURI = etk::String(tmpURI.begin() + 1, tmpURI.end()); tmpURI = etk::String(tmpURI.begin() + 1, tmpURI.end());
} }
// TODO : Remove subParameters xxx?YYY
m_userGateWay = m_routerInterface->get(tmpURI); m_userGateWay = m_routerInterface->get(tmpURI);
APPL_INFO("Connect on client done : '" << tmpURI << "'"); APPL_INFO("Connect on client done : '" << tmpURI << "'");
if (m_userGateWay == nullptr) { if (m_userGateWay == nullptr) {
APPL_ERROR("Can not connect on Client ==> it does not exist ..."); APPL_ERROR("Can not connect on Client ==> it does not exist ...");
return false; return "CLOSE";
} }
return true; uint16_t externalPort = m_userGateWay->getOpenExternalPort();
if (externalPort != 0) {
if (m_interfaceClient.getRemoteAddress().startWith("127.0.0.1:") == true) {
// find a local port ==> can redirect stream.
APPL_WARNING("Request redirect of the connection, because it is possible");
// remove reference on the client befor it was inform of our connection
m_userGateWay->rmClient(sharedFromThis());
m_userGateWay = nullptr;
m_interfaceRedirect = true;
return etk::String("REDIRECT:") + m_routerInterface->propertyClientIp.get() + ":" + etk::toString(externalPort);
}
}
return "OK";
} }
void appl::ClientInterface::start() { void appl::ClientInterface::start() {
@ -73,6 +84,12 @@ void appl::ClientInterface::stop() {
} }
bool appl::ClientInterface::isAlive() { bool appl::ClientInterface::isAlive() {
APPL_ERROR("check if alive");
// kill interface in case of redirection
if (m_interfaceRedirect == true) {
APPL_ERROR(" ===> plop");
return false;
}
//APPL_INFO("is alive : " << m_interfaceClient.isActive()); //APPL_INFO("is alive : " << m_interfaceClient.isActive());
bool ret = m_interfaceClient.isActive(); bool ret = m_interfaceClient.isActive();
if (ret == true) { if (ret == true) {
@ -106,15 +123,15 @@ void appl::ClientInterface::onClientData(ememory::SharedPtr<zeus::Message> _valu
} }
// check correct SourceID // check correct SourceID
if (_value->getSourceId() != m_uid) { if (_value->getSourceId() != m_uid) {
answerProtocolError(transactionId, "message with the wrong source ID : " + etk::toString(_value->getSourceId()) + " != " + etk::toString(m_uid)); answerProtocolError(transactionId, "message with the wrong source ID: " + etk::toString(_value->getSourceId()) + " != " + etk::toString(m_uid));
return; return;
} }
// Check gateway corectly connected // Check gateway corectly connected
if (m_userGateWay == nullptr) { if (m_userGateWay == nullptr) {
answerProtocolError(transactionId, "GateWay error"); answerProtocolError(transactionId, "GateWay error (not connected)");
return; return;
} }
// TODO: Special hook for the first call that we need to get the curretn ID of the connection, think to set this at an other position ... // TODO: Special hook for the first call that we need to get the current ID of the connection, think to set this at an other position ...
if (m_uid == 0) { if (m_uid == 0) {
APPL_INFO("special case, we need to get the ID Of the client:"); APPL_INFO("special case, we need to get the ID Of the client:");
if (_value->getType() != zeus::message::type::call) { if (_value->getType() != zeus::message::type::call) {

View File

@ -17,7 +17,8 @@ namespace appl {
private: private:
appl::Router* m_routerInterface; appl::Router* m_routerInterface;
zeus::WebServer m_interfaceClient; zeus::WebServer m_interfaceClient;
bool requestURI(const etk::String& _uri); bool m_interfaceRedirect = false;
etk::String requestURI(const etk::String& _uri, const etk::Map<etk::String,etk::String>& _options);
public: public:
ememory::SharedPtr<appl::GateWayInterface> m_userGateWay; ememory::SharedPtr<appl::GateWayInterface> m_userGateWay;
uint16_t m_uid; //!< gateway unique ID ==> to have an internal routage ... uint16_t m_uid; //!< gateway unique ID ==> to have an internal routage ...

View File

@ -17,6 +17,7 @@ static const etk::String protocolError = "PROTOCOL-ERROR";
appl::GateWayInterface::GateWayInterface(enet::Tcp _connection, appl::Router* _routerInterface) : appl::GateWayInterface::GateWayInterface(enet::Tcp _connection, appl::Router* _routerInterface) :
m_routerInterface(_routerInterface), m_routerInterface(_routerInterface),
m_interfaceClient(etk::move(_connection), true), m_interfaceClient(etk::move(_connection), true),
m_openExternPort(0),
m_lastSourceID(0x8000) { m_lastSourceID(0x8000) {
ZEUS_INFO("-----------------"); ZEUS_INFO("-----------------");
ZEUS_INFO("-- NEW GateWay --"); ZEUS_INFO("-- NEW GateWay --");
@ -34,31 +35,37 @@ appl::GateWayInterface::~GateWayInterface() {
bool appl::GateWayInterface::isAlive() { bool appl::GateWayInterface::isAlive() {
return m_interfaceClient.isActive(); return m_interfaceClient.isActive();
} }
etk::String appl::GateWayInterface::requestURI(const etk::String& _uri, const etk::Map<etk::String,etk::String>& _options) {
bool appl::GateWayInterface::requestURI(const etk::String& _uri) { ZEUS_INFO("request connect on User - GateWay: '" << _uri << "' from " << m_interfaceClient.getRemoteAddress());
ZEUS_INFO("request connect on User - GateWay: '" << _uri << "'"); for (auto &it: _options) {
ZEUS_INFO(" '" << it.first << "' = '" << it.second << "'");
}
if(m_routerInterface == nullptr) { if(m_routerInterface == nullptr) {
ZEUS_ERROR("Can not access to the main GateWay interface (nullptr)"); ZEUS_ERROR("Can not access to the main GateWay interface (nullptr)");
return false; return "CLOSE";
} }
etk::String tmpURI = _uri; etk::String tmpURI = _uri;
if (tmpURI.size() == 0) { if (tmpURI.size() == 0) {
ZEUS_ERROR("Empty URI ... not supported ..."); ZEUS_ERROR("Empty URI ... not supported ...");
return false; return "CLOSE";
} }
if (tmpURI[0] == '/') { if (tmpURI[0] == '/') {
tmpURI = etk::String(tmpURI.begin() + 1, tmpURI.end()); tmpURI = etk::String(tmpURI.begin() + 1, tmpURI.end());
} }
// TODO : Remove subParameters xxx?YYY
// check if the USER is already connected: // check if the USER is already connected:
bool tmp = m_routerInterface->userIsConnected(tmpURI); bool tmp = m_routerInterface->userIsConnected(tmpURI);
if (tmp == true) { if (tmp == true) {
ZEUS_ERROR("User is already connected ==> this is a big error ..."); ZEUS_ERROR("User is already connected ==> this is a big error ...");
return false; return "CLOSE";
} }
m_name = tmpURI; m_name = tmpURI;
for (auto &it: _options) {
if (it.first == "directAccessPort") {
m_openExternPort = etk::string_to_uint16_t(it.second);
}
}
ZEUS_WARNING("Connection of user : '" << tmpURI << "'"); ZEUS_WARNING("Connection of user : '" << tmpURI << "'");
return true; return "OK";
} }
void appl::GateWayInterface::start() { void appl::GateWayInterface::start() {
@ -78,6 +85,10 @@ void appl::GateWayInterface::send(ememory::SharedPtr<zeus::Message> _data) {
} }
uint16_t appl::GateWayInterface::addClient(ememory::SharedPtr<appl::ClientInterface> _value) { uint16_t appl::GateWayInterface::addClient(ememory::SharedPtr<appl::ClientInterface> _value) {
if (_value == nullptr) {
return -1;
}
APPL_WARNING("Add client on GateWay " << _value->getId());
m_clientConnected.pushBack(_value); m_clientConnected.pushBack(_value);
return m_lastSourceID++; return m_lastSourceID++;
} }
@ -87,14 +98,22 @@ void appl::GateWayInterface::rmClient(ememory::SharedPtr<appl::ClientInterface>
return; return;
} }
uint16_t id = _value->getId(); uint16_t id = _value->getId();
APPL_WARNING("RM client on GateWay : " << id);
bool find = false;
auto it = m_clientConnected.begin(); auto it = m_clientConnected.begin();
while (it != m_clientConnected.end()) { while (it != m_clientConnected.end()) {
if (*it == _value) { if (*it == nullptr) {
it = m_clientConnected.erase(it); it = m_clientConnected.erase(it);
} else if (*it == _value) {
it = m_clientConnected.erase(it);
find = true;
} else { } else {
++it; ++it;
} }
} }
if (find == false) {
return;
}
m_interfaceClient.call(uint32_t(id)<<16, ZEUS_ID_GATEWAY, "removeRouterClient", id); m_interfaceClient.call(uint32_t(id)<<16, ZEUS_ID_GATEWAY, "removeRouterClient", id);
} }
@ -114,6 +133,7 @@ void appl::GateWayInterface::onServiceData(ememory::SharedPtr<zeus::Message> _va
return; return;
} }
m_name = callObj->getParameter<etk::String>(0); m_name = callObj->getParameter<etk::String>(0);
m_openExternPort = callObj->getParameter<uint16_t>(1);
m_interfaceClient.setInterfaceName("srv-" + m_name); m_interfaceClient.setInterfaceName("srv-" + m_name);
m_interfaceClient.answerValue(transactionId, _value->getDestination(), _value->getSource(), true); m_interfaceClient.answerValue(transactionId, _value->getDestination(), _value->getSource(), true);
return; return;

View File

@ -15,10 +15,11 @@ namespace appl {
private: private:
appl::Router* m_routerInterface; appl::Router* m_routerInterface;
zeus::WebServer m_interfaceClient; zeus::WebServer m_interfaceClient;
uint16_t m_openExternPort;
uint16_t m_lastSourceID; //!< The source dynbamic generated ID is manage in 2 part the value <= 0x7FFF is used by the gateway and the value >= 0x8000 is manage by the router uint16_t m_lastSourceID; //!< The source dynbamic generated ID is manage in 2 part the value <= 0x7FFF is used by the gateway and the value >= 0x8000 is manage by the router
etk::Vector<ememory::SharedPtr<appl::ClientInterface>> m_clientConnected; etk::Vector<ememory::SharedPtr<appl::ClientInterface>> m_clientConnected;
etk::String m_name; etk::String m_name;
bool requestURI(const etk::String& _uri); etk::String requestURI(const etk::String& _uri, const etk::Map<etk::String,etk::String>& _options);
public: public:
GateWayInterface(enet::Tcp _connection, appl::Router* _routerInterface); GateWayInterface(enet::Tcp _connection, appl::Router* _routerInterface);
virtual ~GateWayInterface(); virtual ~GateWayInterface();
@ -34,6 +35,13 @@ namespace appl {
return m_name; return m_name;
} }
bool isAlive(); bool isAlive();
/**
* @brief Get the open port for external direct connection on the gateway
* @return Port id or 0 if not open.
*/
uint16_t getOpenExternalPort() const {
return m_openExternPort;
}
protected: protected:
void answerProtocolError(uint32_t _transactionId, const etk::String& _errorHelp); void answerProtocolError(uint32_t _transactionId, const etk::String& _errorHelp);
}; };

View File

@ -16,6 +16,7 @@ class UserAvaillable {
etk::String m_name; etk::String m_name;
etk::String m_basePath; etk::String m_basePath;
bool m_accessMediaCenter; bool m_accessMediaCenter;
bool m_enableDirectAccess;
FILE* m_subProcess; FILE* m_subProcess;
}; };
etk::Vector<UserAvaillable> g_listUserAvaillable; etk::Vector<UserAvaillable> g_listUserAvaillable;
@ -35,6 +36,7 @@ static void store_db() {
propObject.add("name", ejson::String(it.m_name)); propObject.add("name", ejson::String(it.m_name));
propObject.add("path", ejson::String(it.m_basePath)); propObject.add("path", ejson::String(it.m_basePath));
propObject.add("access-media-center", ejson::Boolean(it.m_accessMediaCenter)); propObject.add("access-media-center", ejson::Boolean(it.m_accessMediaCenter));
propObject.add("access-direct", ejson::Boolean(it.m_enableDirectAccess));
} }
bool retGenerate = database.storeSafe(g_pathDBName); bool retGenerate = database.storeSafe(g_pathDBName);
APPL_ERROR("Store database [STOP] : " << g_pathDBName << " ret = " << retGenerate); APPL_ERROR("Store database [STOP] : " << g_pathDBName << " ret = " << retGenerate);
@ -55,6 +57,7 @@ static void load_db() {
userProperty.m_name = userElement["name"].toString().get(); userProperty.m_name = userElement["name"].toString().get();
userProperty.m_basePath = userElement["path"].toString().get(); userProperty.m_basePath = userElement["path"].toString().get();
userProperty.m_accessMediaCenter = userElement["access-media-center"].toBoolean().get(); userProperty.m_accessMediaCenter = userElement["access-media-center"].toBoolean().get();
userProperty.m_enableDirectAccess = userElement["access-direct"].toBoolean().get();
APPL_INFO("find USER: '" << userProperty.m_name << "'"); APPL_INFO("find USER: '" << userProperty.m_name << "'");
g_listUserAvaillable.pushBack(userProperty); g_listUserAvaillable.pushBack(userProperty);
} }
@ -141,7 +144,9 @@ appl::Router::Router() :
propertyGateWayIp(this, "gw-ip", "127.0.0.1", "Ip to listen Gateway", &appl::Router::onPropertyChangeGateWayIp), propertyGateWayIp(this, "gw-ip", "127.0.0.1", "Ip to listen Gateway", &appl::Router::onPropertyChangeGateWayIp),
propertyGateWayPort(this, "gw-port", 1984, "Port to listen Gateway", &appl::Router::onPropertyChangeGateWayPort), propertyGateWayPort(this, "gw-port", 1984, "Port to listen Gateway", &appl::Router::onPropertyChangeGateWayPort),
propertyGateWayMax(this, "gw-max", 8000, "Maximum of Gateway at the same time", &appl::Router::onPropertyChangeGateWayMax), propertyGateWayMax(this, "gw-max", 8000, "Maximum of Gateway at the same time", &appl::Router::onPropertyChangeGateWayMax),
propertyDelayToStop(this, "delay-to-stop", 0, "Delay before the client stop the connection in second (default: 0=automatic set by the gateway; -1=never disconnect; other the time )") { propertyDelayToStop(this, "delay-to-stop", 0, "Delay before the client stop the connection in second (default: 0=automatic set by the gateway; -1=never disconnect; other the time )"),
propertyGateWayDirectPortMin(this, "gw-direct-port-min", 12000, "Minimum of Gateway at the same time"),
propertyGateWayDirectPortMax(this, "gw-direct-port-max", 13000, "Maximum of Gateway at the same time") {
m_interfaceClientServer = ememory::makeShared<appl::TcpServerInput>(this, false); m_interfaceClientServer = ememory::makeShared<appl::TcpServerInput>(this, false);
m_interfaceGateWayServer = ememory::makeShared<appl::TcpServerInput>(this, true); m_interfaceGateWayServer = ememory::makeShared<appl::TcpServerInput>(this, true);
load_db(); load_db();
@ -234,9 +239,14 @@ ememory::SharedPtr<appl::GateWayInterface> appl::Router::get(const etk::String&
//etk::String logFile = " "; //etk::String logFile = " ";
APPL_INFO("New Child log in = " << logFile); APPL_INFO("New Child log in = " << logFile);
} }
etk::String directAccess;
if (it.m_enableDirectAccess == true) {
directAccess = "--direct-ip=" + *propertyClientIp;
directAccess += " --direct-port=" + etk::toString(*propertyGateWayDirectPortMin);
}
etk::String delay = "--router-delay=" + etk::toString(*propertyDelayToStop); etk::String delay = "--router-delay=" + etk::toString(*propertyDelayToStop);
//etk::String delay = "--router-delay=-1"; //etk::String delay = "--router-delay=-1";
APPL_INFO("execute: " << binary << " " << userConf << " --srv=all " << delay << " " << basePath << " " << logFile); APPL_INFO("execute: " << binary << " " << userConf << " --srv=all " << delay << " " << basePath << " " << logFile << " " << directAccess);
int ret = execlp( binary.c_str(), int ret = execlp( binary.c_str(),
binary.c_str(), // must repeate the binary name to have the name as first argument ... binary.c_str(), // must repeate the binary name to have the name as first argument ...
userConf.c_str(), userConf.c_str(),
@ -245,6 +255,7 @@ ememory::SharedPtr<appl::GateWayInterface> appl::Router::get(const etk::String&
delay.c_str(), delay.c_str(),
basePath.c_str(), basePath.c_str(),
logFile.c_str(), logFile.c_str(),
directAccess.c_str(),
NULL); NULL);
APPL_ERROR("Child Execution ret = " << ret); APPL_ERROR("Child Execution ret = " << ret);
exit (-1); exit (-1);
@ -307,7 +318,9 @@ void appl::Router::cleanIO() {
if (*it2 != nullptr) { if (*it2 != nullptr) {
if ((*it2)->isAlive() == false) { if ((*it2)->isAlive() == false) {
(*it2)->stop(); (*it2)->stop();
APPL_ERROR("count = " << (*it2).useCount() << " list.size()=" << m_clientList.size());
it2 = m_clientList.erase(it2); it2 = m_clientList.erase(it2);
APPL_ERROR(" list.size()=" << m_clientList.size());
APPL_INFO("remove DONE ... "); APPL_INFO("remove DONE ... ");
continue; continue;
} }

View File

@ -19,7 +19,6 @@ namespace appl {
etk::Vector<ememory::SharedPtr<appl::ClientInterface>> m_clientList; //!< List of all Client interface with their own connection etk::Vector<ememory::SharedPtr<appl::ClientInterface>> m_clientList; //!< List of all Client interface with their own connection
ememory::SharedPtr<appl::TcpServerInput> m_interfaceClientServer; ememory::SharedPtr<appl::TcpServerInput> m_interfaceClientServer;
ememory::SharedPtr<appl::TcpServerInput> m_interfaceGateWayServer; ememory::SharedPtr<appl::TcpServerInput> m_interfaceGateWayServer;
ejson::Document m_listUser;
public: public:
eproperty::Value<bool> propertyStdOut; //!< not set the log in the stdout or in the local file eproperty::Value<bool> propertyStdOut; //!< not set the log in the stdout or in the local file
eproperty::Value<etk::String> propertyClientIp; eproperty::Value<etk::String> propertyClientIp;
@ -29,6 +28,8 @@ namespace appl {
eproperty::Value<uint16_t> propertyGateWayPort; eproperty::Value<uint16_t> propertyGateWayPort;
eproperty::Value<uint16_t> propertyGateWayMax; eproperty::Value<uint16_t> propertyGateWayMax;
eproperty::Value<int32_t> propertyDelayToStop; eproperty::Value<int32_t> propertyDelayToStop;
eproperty::Value<uint16_t> propertyGateWayDirectPortMin;
eproperty::Value<uint16_t> propertyGateWayDirectPortMax;
public: public:
Router(); Router();
virtual ~Router(); virtual ~Router();

View File

@ -43,13 +43,13 @@ int main(int _argc, const char *_argv[]) {
APPL_PRINT(etk::getApplicationName() << " - help : "); APPL_PRINT(etk::getApplicationName() << " - help : ");
APPL_PRINT(" " << _argv[0] << " [options]"); APPL_PRINT(" " << _argv[0] << " [options]");
APPL_PRINT(" --stdout stdout log"); APPL_PRINT(" --stdout stdout log");
APPL_PRINT(" --client-ip=XXX Client connection IP (default: 127.0.0.1)"); APPL_PRINT(" --client-ip=XXX Client connection IP (default: " << basicRouter.propertyClientIp.get() << ")");
APPL_PRINT(" --client-port=XXX Client connection PORT (default: 1983)"); APPL_PRINT(" --client-port=XXX Client connection PORT (default: " << basicRouter.propertyClientPort.get() << ")");
APPL_PRINT(" --client-max=XXX Client Maximum parallele connection (default: 80)"); APPL_PRINT(" --client-max=XXX Client Maximum parallele connection (default: " << basicRouter.propertyClientMax.get() << ")");
APPL_PRINT(" --gw-ip=XXX Gateway connection IP (default: 127.0.0.1)"); APPL_PRINT(" --gw-ip=XXX Gateway connection IP (default: " << basicRouter.propertyGateWayIp.get() << ")");
APPL_PRINT(" --gw-port=XXX Gateway connection PORT (default: 1984)"); APPL_PRINT(" --gw-port=XXX Gateway connection PORT (default: " << basicRouter.propertyGateWayPort.get() << ")");
APPL_PRINT(" --gw-max=XXX Gateway Maximum IO (default: 15)"); APPL_PRINT(" --gw-max=XXX Gateway Maximum IO (default: " << basicRouter.propertyGateWayMax.get() << ")");
APPL_PRINT(" --delay-stop-user=XXX Delay before the client stop the connection in second (default: 0=automatic set by the gateway; -1=never disconnect; other the time )"); APPL_PRINT(" --delay-stop-user=XXX Delay before the client stop the connection in second (default: " << basicRouter.propertyDelayToStop.get() << "0=automatic set by the gateway; -1=never disconnect; other the time )");
return -1; return -1;
} }
} }