[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("-------------------");
}
bool appl::ClientInterface::requestURI(const etk::String& _uri) {
APPL_WARNING("request connect on CLIENT: '" << _uri << "'");
etk::String appl::ClientInterface::requestURI(const etk::String& _uri, const etk::Map<etk::String,etk::String>& _options) {
APPL_INFO("request connect on CLIENT: '" << _uri << "' from " << m_interfaceClient.getRemoteAddress());
if(m_routerInterface == nullptr) {
APPL_ERROR("Can not access to the main GateWay interface (nullptr)");
return false;
return "CLOSE";
}
etk::String tmpURI = _uri;
if (tmpURI.size() == 0) {
APPL_ERROR("Empty URI ... not supported ...");
return false;
return "CLOSE";
}
if (tmpURI[0] == '/') {
tmpURI = etk::String(tmpURI.begin() + 1, tmpURI.end());
}
// TODO : Remove subParameters xxx?YYY
m_userGateWay = m_routerInterface->get(tmpURI);
APPL_INFO("Connect on client done : '" << tmpURI << "'");
if (m_userGateWay == nullptr) {
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() {
@ -73,6 +84,12 @@ void appl::ClientInterface::stop() {
}
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());
bool ret = m_interfaceClient.isActive();
if (ret == true) {
@ -106,15 +123,15 @@ void appl::ClientInterface::onClientData(ememory::SharedPtr<zeus::Message> _valu
}
// check correct SourceID
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;
}
// Check gateway corectly connected
if (m_userGateWay == nullptr) {
answerProtocolError(transactionId, "GateWay error");
answerProtocolError(transactionId, "GateWay error (not connected)");
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) {
APPL_INFO("special case, we need to get the ID Of the client:");
if (_value->getType() != zeus::message::type::call) {

View File

@ -17,7 +17,8 @@ namespace appl {
private:
appl::Router* m_routerInterface;
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:
ememory::SharedPtr<appl::GateWayInterface> m_userGateWay;
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) :
m_routerInterface(_routerInterface),
m_interfaceClient(etk::move(_connection), true),
m_openExternPort(0),
m_lastSourceID(0x8000) {
ZEUS_INFO("-----------------");
ZEUS_INFO("-- NEW GateWay --");
@ -34,31 +35,37 @@ appl::GateWayInterface::~GateWayInterface() {
bool appl::GateWayInterface::isAlive() {
return m_interfaceClient.isActive();
}
bool appl::GateWayInterface::requestURI(const etk::String& _uri) {
ZEUS_INFO("request connect on User - GateWay: '" << _uri << "'");
etk::String appl::GateWayInterface::requestURI(const etk::String& _uri, const etk::Map<etk::String,etk::String>& _options) {
ZEUS_INFO("request connect on User - GateWay: '" << _uri << "' from " << m_interfaceClient.getRemoteAddress());
for (auto &it: _options) {
ZEUS_INFO(" '" << it.first << "' = '" << it.second << "'");
}
if(m_routerInterface == nullptr) {
ZEUS_ERROR("Can not access to the main GateWay interface (nullptr)");
return false;
return "CLOSE";
}
etk::String tmpURI = _uri;
if (tmpURI.size() == 0) {
ZEUS_ERROR("Empty URI ... not supported ...");
return false;
return "CLOSE";
}
if (tmpURI[0] == '/') {
tmpURI = etk::String(tmpURI.begin() + 1, tmpURI.end());
}
// TODO : Remove subParameters xxx?YYY
// check if the USER is already connected:
bool tmp = m_routerInterface->userIsConnected(tmpURI);
if (tmp == true) {
ZEUS_ERROR("User is already connected ==> this is a big error ...");
return false;
return "CLOSE";
}
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 << "'");
return true;
return "OK";
}
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) {
if (_value == nullptr) {
return -1;
}
APPL_WARNING("Add client on GateWay " << _value->getId());
m_clientConnected.pushBack(_value);
return m_lastSourceID++;
}
@ -87,14 +98,22 @@ void appl::GateWayInterface::rmClient(ememory::SharedPtr<appl::ClientInterface>
return;
}
uint16_t id = _value->getId();
APPL_WARNING("RM client on GateWay : " << id);
bool find = false;
auto it = m_clientConnected.begin();
while (it != m_clientConnected.end()) {
if (*it == _value) {
if (*it == nullptr) {
it = m_clientConnected.erase(it);
} else if (*it == _value) {
it = m_clientConnected.erase(it);
find = true;
} else {
++it;
}
}
if (find == false) {
return;
}
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;
}
m_name = callObj->getParameter<etk::String>(0);
m_openExternPort = callObj->getParameter<uint16_t>(1);
m_interfaceClient.setInterfaceName("srv-" + m_name);
m_interfaceClient.answerValue(transactionId, _value->getDestination(), _value->getSource(), true);
return;

View File

@ -15,10 +15,11 @@ namespace appl {
private:
appl::Router* m_routerInterface;
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
etk::Vector<ememory::SharedPtr<appl::ClientInterface>> m_clientConnected;
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:
GateWayInterface(enet::Tcp _connection, appl::Router* _routerInterface);
virtual ~GateWayInterface();
@ -34,6 +35,13 @@ namespace appl {
return m_name;
}
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:
void answerProtocolError(uint32_t _transactionId, const etk::String& _errorHelp);
};

View File

@ -16,6 +16,7 @@ class UserAvaillable {
etk::String m_name;
etk::String m_basePath;
bool m_accessMediaCenter;
bool m_enableDirectAccess;
FILE* m_subProcess;
};
etk::Vector<UserAvaillable> g_listUserAvaillable;
@ -35,6 +36,7 @@ static void store_db() {
propObject.add("name", ejson::String(it.m_name));
propObject.add("path", ejson::String(it.m_basePath));
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);
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_basePath = userElement["path"].toString().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 << "'");
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),
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),
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_interfaceGateWayServer = ememory::makeShared<appl::TcpServerInput>(this, true);
load_db();
@ -234,9 +239,14 @@ ememory::SharedPtr<appl::GateWayInterface> appl::Router::get(const etk::String&
//etk::String 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=-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(),
binary.c_str(), // must repeate the binary name to have the name as first argument ...
userConf.c_str(),
@ -245,6 +255,7 @@ ememory::SharedPtr<appl::GateWayInterface> appl::Router::get(const etk::String&
delay.c_str(),
basePath.c_str(),
logFile.c_str(),
directAccess.c_str(),
NULL);
APPL_ERROR("Child Execution ret = " << ret);
exit (-1);
@ -307,7 +318,9 @@ void appl::Router::cleanIO() {
if (*it2 != nullptr) {
if ((*it2)->isAlive() == false) {
(*it2)->stop();
APPL_ERROR("count = " << (*it2).useCount() << " list.size()=" << m_clientList.size());
it2 = m_clientList.erase(it2);
APPL_ERROR(" list.size()=" << m_clientList.size());
APPL_INFO("remove DONE ... ");
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
ememory::SharedPtr<appl::TcpServerInput> m_interfaceClientServer;
ememory::SharedPtr<appl::TcpServerInput> m_interfaceGateWayServer;
ejson::Document m_listUser;
public:
eproperty::Value<bool> propertyStdOut; //!< not set the log in the stdout or in the local file
eproperty::Value<etk::String> propertyClientIp;
@ -29,6 +28,8 @@ namespace appl {
eproperty::Value<uint16_t> propertyGateWayPort;
eproperty::Value<uint16_t> propertyGateWayMax;
eproperty::Value<int32_t> propertyDelayToStop;
eproperty::Value<uint16_t> propertyGateWayDirectPortMin;
eproperty::Value<uint16_t> propertyGateWayDirectPortMax;
public:
Router();
virtual ~Router();

View File

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