espcfg.cpp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #pragma warning( disable : 4786 )
  14. #ifdef _WIN32
  15. //#define ESP_SUPPORT_DALI_CONFIG
  16. //CRT
  17. #include <process.h>
  18. #endif
  19. //Jlib
  20. #include "jliball.hpp"
  21. //SCM Interfaces
  22. #include "esp.hpp"
  23. #include "espplugin.hpp"
  24. #include "espplugin.ipp"
  25. #include "espcfg.ipp"
  26. #include "xslprocessor.hpp"
  27. #include "mplog.hpp"
  28. #include "rmtfile.hpp"
  29. #include "dafdesc.hpp"
  30. //#include <dalienv.hpp>
  31. /*
  32. #if defined(USING_MPATROL)
  33. #define ESP_BUILTIN
  34. #endif
  35. */
  36. //#define ESP_BUILTIN
  37. extern "C" {
  38. ESP_FACTORY IEspService * esp_service_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process);
  39. ESP_FACTORY IEspRpcBinding * esp_binding_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process);
  40. ESP_FACTORY IEspProtocol * esp_protocol_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process);
  41. };
  42. #ifdef ESP_BUILTIN
  43. builtin espdirect;
  44. #endif
  45. // add suffix and prefix when necessary
  46. void fixPlugin(StringBuffer& plugin)
  47. {
  48. if (stricmp(plugin.str()+plugin.length()-sizeof(SharedObjectExtension)+1,SharedObjectExtension)==0)
  49. return;
  50. plugin.insert(0,SharedObjectPrefix);
  51. plugin.append(SharedObjectExtension);
  52. }
  53. void CEspConfig::loadBuiltIns()
  54. {
  55. #ifdef ESP_BUILTIN
  56. espdirect.prot = esp_protocol_factory;
  57. espdirect.bind = esp_binding_factory;
  58. espdirect.serv = esp_service_factory;
  59. #endif
  60. }
  61. builtin *CEspConfig::getBuiltIn(string name)
  62. {
  63. #ifdef ESP_BUILTIN
  64. //if (name.compare("pixall.dll")==0 || name.compare("pixall.so")==0)
  65. return &espdirect;
  66. #else //ESP_DIRECT
  67. return NULL;
  68. #endif
  69. }
  70. StringBuffer &CVSBuildToEspVersion(char const * tag, StringBuffer & out)
  71. {
  72. unsigned build = 0;
  73. unsigned subbuild = 0;
  74. while(!isdigit(*tag))
  75. {
  76. if(!*tag) break;
  77. tag++;
  78. }
  79. while(isdigit(*tag))
  80. {
  81. if(!*tag) break;
  82. build = 10*build + (*tag-'0');
  83. tag++;
  84. }
  85. if(isalpha(*tag))
  86. {
  87. if(islower(*tag))
  88. subbuild = *tag-'a'+1;
  89. else
  90. subbuild = *tag-'A'+1;
  91. }
  92. out.append(build/10).append('.').append(build%10).append(subbuild);
  93. return out;
  94. }
  95. int CSessionCleaner::run()
  96. {
  97. try
  98. {
  99. PROGLOG("CSessionCleaner Thread started.");
  100. VStringBuffer xpath("%s*", PathSessionSession);
  101. int checkSessionTimeoutMillSeconds = checkSessionTimeoutSeconds * 1000;
  102. while(!stopping)
  103. {
  104. if (!m_isDetached)
  105. {
  106. Owned<IRemoteConnection> conn = getSDSConnectionWithRetry(espSessionSDSPath.get(), RTM_LOCK_WRITE, SDSSESSION_CONNECT_TIMEOUTMS);
  107. if (!conn)
  108. throw MakeStringException(-1, "Failed to connect to %s.", PathSessionRoot);
  109. CDateTime now;
  110. now.setNow();
  111. time_t timeNow = now.getSimple();
  112. Owned<IPropertyTreeIterator> iter1 = conn->queryRoot()->getElements(PathSessionApplication);
  113. ForEach(*iter1)
  114. {
  115. ICopyArrayOf<IPropertyTree> toRemove;
  116. Owned<IPropertyTreeIterator> iter2 = iter1->query().getElements(xpath.str());
  117. ForEach(*iter2)
  118. {
  119. IPropertyTree& item = iter2->query();
  120. if (timeNow >= item.getPropInt64(PropSessionTimeoutAt, 0))
  121. toRemove.append(item);
  122. }
  123. ForEachItemIn(i, toRemove)
  124. {
  125. iter1->query().removeTree(&toRemove.item(i));
  126. }
  127. }
  128. }
  129. sem.wait(checkSessionTimeoutMillSeconds);
  130. }
  131. }
  132. catch(IException *e)
  133. {
  134. StringBuffer msg;
  135. IERRLOG("CSessionCleaner::run() Exception %d:%s", e->errorCode(), e->errorMessage(msg).str());
  136. e->Release();
  137. }
  138. catch(...)
  139. {
  140. IERRLOG("Unknown CSessionCleaner::run() Exception");
  141. }
  142. return 0;
  143. }
  144. void CSessionCleaner::stop()
  145. {
  146. stopping = true;
  147. sem.signal();
  148. join();
  149. }
  150. void CEspConfig::readSessionDomainsSetting()
  151. {
  152. bool hasAuthDomainSettings = false;
  153. bool hasSessionAuth = false;
  154. bool hasDefaultSessionDomain = false;
  155. Owned<IPropertyTree> proc_cfg = getProcessConfig(m_envpt, m_process.str());
  156. Owned<IPropertyTreeIterator> it = proc_cfg->getElements("AuthDomains/AuthDomain");
  157. ForEach(*it)
  158. {
  159. hasAuthDomainSettings = true;
  160. IPropertyTree& authDomain = it->query();
  161. const char* authType = authDomain.queryProp("@authType");
  162. if (isEmptyString(authType) || (!strieq(authType, "AuthPerSessionOnly") && !strieq(authType, "AuthTypeMixed")))
  163. continue;
  164. hasSessionAuth = true;
  165. int clientSessionTimeoutSeconds;
  166. int clientSessionTimeoutMinutes = authDomain.getPropInt("@clientSessionTimeoutMinutes", ESP_SESSION_TIMEOUT);
  167. if (clientSessionTimeoutMinutes < 0)
  168. clientSessionTimeoutSeconds = ESP_SESSION_NEVER_TIMEOUT;
  169. else
  170. clientSessionTimeoutSeconds = clientSessionTimeoutMinutes * 60;
  171. //The serverSessionTimeoutMinutes is used to clean the sessions by ESP server after the sessions have been timed out on ESP clients.
  172. //Considering possible network delay, serverSessionTimeoutMinutes should be greater than clientSessionTimeoutMinutes.
  173. int serverSessionTimeoutMinutes = authDomain.getPropInt("@serverSessionTimeoutMinutes", 0);
  174. if ((serverSessionTimeoutMinutes < 0) || (clientSessionTimeoutMinutes < 0))
  175. serverSessionTimeoutSeconds = ESP_SESSION_NEVER_TIMEOUT;
  176. else
  177. serverSessionTimeoutSeconds = serverSessionTimeoutMinutes * 60;
  178. if (serverSessionTimeoutSeconds < clientSessionTimeoutSeconds)
  179. serverSessionTimeoutSeconds = 2 * clientSessionTimeoutSeconds;
  180. const char* authDomainName = authDomain.queryProp("@domainName");
  181. if (isEmptyString(authDomainName) || strieq(authDomainName, "default"))
  182. {
  183. if (hasDefaultSessionDomain)
  184. throw MakeStringException(-1, ">1 AuthDomains are not named.");
  185. hasDefaultSessionDomain = true;
  186. }
  187. }
  188. //Ensure SDS Session tree if there is session auth or there is no AuthDomain setting (ex. old environment.xml)
  189. if (hasSessionAuth || !hasAuthDomainSettings)
  190. sdsSessionNeeded = true;
  191. }
  192. void CEspConfig::ensureSDSSession()
  193. {
  194. Owned<IRemoteConnection> conn = getSDSConnectionWithRetry(PathSessionRoot, RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDSSESSION_CONNECT_TIMEOUTMS);
  195. if (!conn)
  196. throw makeStringExceptionV(-1, "Failed to connect to %s.", PathSessionRoot);
  197. IPropertyTree* sessionRoot = conn->queryRoot();
  198. VStringBuffer xpath("%s[@name=\"%s\"]", PathSessionProcess, m_process.str());
  199. IPropertyTree* processSessionTree = sessionRoot->queryBranch(xpath);
  200. if (!processSessionTree)
  201. {
  202. processSessionTree = sessionRoot->addPropTree(PathSessionProcess);
  203. processSessionTree->setProp("@name", m_process);
  204. }
  205. ensureSDSSessionApplications(processSessionTree);
  206. sdsSessionEnsured = true;
  207. if (serverSessionTimeoutSeconds != ESP_SESSION_NEVER_TIMEOUT)
  208. {
  209. VStringBuffer espSessionSDSPath("%s/%s[@name=\"%s\"]", PathSessionRoot, PathSessionProcess, m_process.str());
  210. Owned<IPropertyTree> proc_cfg = getProcessConfig(m_envpt, m_process);
  211. m_sessionCleaner.setown(new CSessionCleaner(espSessionSDSPath.str(), proc_cfg->getPropInt("@checkSessionTimeoutSeconds",
  212. ESP_CHECK_SESSION_TIMEOUT)));
  213. m_sessionCleaner->start();
  214. }
  215. }
  216. void CEspConfig::ensureSDSSessionApplications(IPropertyTree* espSession)
  217. {
  218. std::list<int> bindingPorts;
  219. for (const auto pbfg: m_bindings)
  220. {
  221. auto it = std::find(bindingPorts.begin(), bindingPorts.end(), pbfg->port);
  222. if (it == bindingPorts.end())
  223. bindingPorts.push_back(pbfg->port);
  224. }
  225. if (bindingPorts.empty())
  226. throw makeStringException(-1, "No binding port.");
  227. for (const auto port: bindingPorts)
  228. {
  229. VStringBuffer appStr("%s[@port=\"%d\"]", PathSessionApplication, port);
  230. IPropertyTree* appSessionTree = espSession->queryBranch(appStr.str());
  231. if (!appSessionTree)
  232. {
  233. IPropertyTree* newAppSessionTree = espSession->addPropTree(PathSessionApplication);
  234. newAppSessionTree->setPropInt("@port", port);
  235. }
  236. }
  237. }
  238. CEspConfig::CEspConfig(IProperties* inputs, IPropertyTree* envpt, IPropertyTree* procpt, bool isDali)
  239. {
  240. hsami_=0;
  241. serverstatus=NULL;
  242. useDali=false;
  243. if(inputs)
  244. m_inputs.setown(inputs);
  245. if(!envpt || !procpt)
  246. return;
  247. m_envpt.setown(envpt);
  248. m_cfg.setown(procpt);
  249. loadBuiltIns();
  250. // load options
  251. const char* level = m_cfg->queryProp("@logLevel");
  252. m_options.logLevel = level ? atoi(level) : LogMin;
  253. m_options.logReq = readLogRequest(m_cfg->queryProp("@logRequests"));
  254. m_options.logResp = m_cfg->getPropBool("@logResponses", false);
  255. m_options.txSummaryLevel = m_cfg->getPropInt("@txSummaryLevel", LogMin);
  256. m_options.txSummaryStyle = readTxSummaryStyle(m_cfg->queryProp("@txSummaryStyle"));
  257. m_options.txSummaryGroup = readTxSummaryGroup(m_cfg->queryProp("@txSummaryGroup"));
  258. m_options.txSummaryResourceReq = m_cfg->getPropBool("@txSummaryResourceReq", false);
  259. m_options.frameTitle.set(m_cfg->queryProp("@name"));
  260. m_options.slowProcessingTime = m_cfg->getPropInt("@slowProcessingTime", 30) * 1000; //in msec
  261. if (!m_cfg->getProp("@name", m_process))
  262. {
  263. OERRLOG("EspProcess name not found");
  264. }
  265. else
  266. {
  267. DBGLOG("ESP process name [%s]", m_process.str());
  268. setIsDetachedFromDali(false);
  269. setIsSubscribedToDali(true);
  270. try
  271. {
  272. StringBuffer procDirectory;
  273. m_cfg->getProp("@directory", procDirectory);
  274. if (!procDirectory.isEmpty())
  275. {
  276. m_daliAttachStateFileName.setf("%s%c%s-AttachState.xml",procDirectory.str(), PATHSEPCHAR, m_process.str());
  277. try
  278. {
  279. Owned<IPTree> espProcAttachState = createPTreeFromXMLFile(m_daliAttachStateFileName);
  280. if (espProcAttachState)
  281. {
  282. setIsDetachedFromDali(!(espProcAttachState->getPropBool("@attached", true)));
  283. setIsSubscribedToDali(espProcAttachState->getPropBool("@subscribed", true));
  284. }
  285. else
  286. {
  287. ESPLOG(LogMin, "Could not load DALI Attach state file [%s] for ESP process [%s]", m_daliAttachStateFileName.str(), m_process.str());
  288. }
  289. }
  290. catch (...)
  291. {
  292. ESPLOG(LogMin, "Could not load DALI Attach state file [%s] for ESP process [%s]", m_daliAttachStateFileName.str(), m_process.str());
  293. }
  294. saveAttachState();
  295. }
  296. else
  297. ESPLOG(LogMin, "ESP Process [%s] configuration is missing '@directory' attribute, could not read AttachState", m_process.str());
  298. }
  299. catch (IException* e)
  300. {
  301. e->Release();
  302. ESPLOG(LogMin, "Could not load DALI Attach state file [%s] for ESP process [%s]", m_daliAttachStateFileName.str(), m_process.str());
  303. }
  304. catch (...)
  305. {
  306. ESPLOG(LogMin, "Could not load DALI Attach state file [%s] for ESP process [%s]", m_daliAttachStateFileName.str(), m_process.str());
  307. }
  308. if (isDetachedFromDali())
  309. OWARNLOG("ESP Process [%s] loading in DALI DETACHED state - Some ESP services do not load in detached state!", m_process.str());
  310. StringBuffer daliservers;
  311. if (m_cfg->getProp("@daliServers", daliservers))
  312. initDali(daliservers.str()); //won't init if detached
  313. #ifndef _CONTAINERIZED
  314. // Copy the 'cost' tree as provided in environment.xml to the globalConfiguration IPropertyTree,
  315. // so that it is available to the functions that calculate storage and workunit costs
  316. // (Thor, hThor and eclagent are already using globalConfiguration, so this copying is not nessary anywhere else)
  317. IPropertyTree * espConfigCost = m_envpt->queryPropTree("cost");
  318. if (espConfigCost)
  319. {
  320. Owned <IPropertyTree> global = getGlobalConfig();
  321. IPropertyTree * cost = global->hasProp("cost") ? global->queryPropTree("cost") : global->addPropTree("cost");
  322. mergeConfiguration(*cost, *espConfigCost, nullptr, false);
  323. }
  324. #endif
  325. initializeStorageGroups(daliClientActive());
  326. const unsigned dafilesrvConnectTimeout = m_cfg->getPropInt("@dafilesrvConnectTimeout", 10)*1000;
  327. const unsigned dafilesrvReadTimeout = m_cfg->getPropInt("@dafilesrvReadTimeout", 10)*1000;
  328. setRemoteFileTimeouts(dafilesrvConnectTimeout, dafilesrvReadTimeout);
  329. #ifndef _CONTAINERIZED
  330. #ifndef _DEBUG
  331. startPerformanceMonitor(m_cfg->getPropInt("@perfReportDelay", 60)*1000);
  332. #endif
  333. #endif
  334. IPropertyTreeIterator *pt_iter = NULL;
  335. StringBuffer xpath;
  336. if (m_inputs->hasProp("SingleUserPass"))
  337. {
  338. StringBuffer plainesppass;
  339. StringBuffer encesppass;
  340. m_inputs->getProp("SingleUserPass", plainesppass);
  341. encrypt(encesppass, plainesppass.str());
  342. xpath.setf("SecurityManagers/SecurityManager[@type=\"SingleUserSecurityManager\"]/SingleUserSecurityManager/");
  343. pt_iter = m_cfg->getElements(xpath.str());
  344. if (pt_iter!=NULL)
  345. {
  346. IPropertyTree *ptree = NULL;
  347. pt_iter->first();
  348. while(pt_iter->isValid())
  349. {
  350. ptree = &pt_iter->query();
  351. if (ptree)
  352. {
  353. ptree->setProp("@SingleUserPass", encesppass.str());
  354. if (m_inputs->hasProp("SingleUserName"))
  355. {
  356. StringBuffer espusername;
  357. m_inputs->getProp("SingleUserName", espusername);
  358. ptree->setProp("@SingleUserName", espusername.str());
  359. }
  360. }
  361. pt_iter->next();
  362. }
  363. pt_iter->Release();
  364. pt_iter=NULL;
  365. }
  366. }
  367. //get the local computer name:
  368. m_cfg->getProp("@computer", m_computer);
  369. //get the local computer information:
  370. xpath.setf("Hardware/Computer[@name=\"%s\"]", m_computer.str());
  371. IPropertyTree *computer = m_envpt->queryPropTree(xpath.str());
  372. if (computer)
  373. {
  374. StringBuffer address;
  375. computer->getProp("@netAddress", address);
  376. int port = m_cfg->getPropInt("@port", 1500);
  377. if(strcmp(address.str(), ".") == 0)
  378. {
  379. GetHostName(address.clear());
  380. }
  381. m_address.set(address.str(), (unsigned short) port);
  382. }
  383. xpath.clear();
  384. xpath.append("EspService");
  385. pt_iter = m_cfg->getElements(xpath.str());
  386. if (pt_iter!=NULL)
  387. {
  388. IPropertyTree *ptree = NULL;
  389. pt_iter->first();
  390. while(pt_iter->isValid())
  391. {
  392. ptree = &pt_iter->query();
  393. if (ptree)
  394. {
  395. srv_cfg *svcfg = new srv_cfg;
  396. ptree->getProp("@name", svcfg->name);
  397. ptree->getProp("@type", svcfg->type);
  398. ptree->getProp("@plugin", svcfg->plugin);
  399. fixPlugin(svcfg->plugin);
  400. map<string, srv_cfg*>::value_type en(svcfg->name.str(), svcfg);
  401. m_services.insert(en);
  402. }
  403. pt_iter->next();
  404. }
  405. pt_iter->Release();
  406. pt_iter=NULL;
  407. }
  408. xpath.clear();
  409. xpath.append("EspProtocol");
  410. pt_iter = m_cfg->getElements(xpath.str());
  411. if (pt_iter!=NULL)
  412. {
  413. IPropertyTree *ptree = NULL;
  414. pt_iter->first();
  415. while(pt_iter->isValid())
  416. {
  417. ptree = &pt_iter->query();
  418. if (ptree)
  419. {
  420. protocol_cfg *pcfg = new protocol_cfg;
  421. ptree->getProp("@name", pcfg->name);
  422. ptree->getProp("@plugin", pcfg->plugin);
  423. fixPlugin(pcfg->plugin);
  424. ptree->getProp("@type", pcfg->type);
  425. map<string, protocol_cfg*>::value_type en(pcfg->name.str(), pcfg);
  426. m_protocols.insert(en);
  427. }
  428. pt_iter->next();
  429. }
  430. pt_iter->Release();
  431. pt_iter=NULL;
  432. }
  433. xpath.clear();
  434. xpath.append("EspBinding");
  435. pt_iter = m_cfg->getElements(xpath.str());
  436. if (pt_iter!=NULL)
  437. {
  438. IPropertyTree *ptree = NULL;
  439. pt_iter->first();
  440. while(pt_iter->isValid())
  441. {
  442. ptree = &pt_iter->query();
  443. if (ptree)
  444. {
  445. OwnedPtr<binding_cfg> bcfg(new binding_cfg);
  446. ptree->getProp("@name", bcfg->name);
  447. bcfg->port = ptree->getPropInt("@port", 0);
  448. if (bcfg->port == 0)
  449. DBGLOG("Binding %s is configured with port 0, it will not be loaded.", bcfg->name.str());
  450. else
  451. {
  452. ptree->getProp("@type", bcfg->type);
  453. if (!streq(bcfg->type.str(), "EsdlBinding"))
  454. {
  455. ptree->getProp("@plugin", bcfg->plugin);
  456. fixPlugin(bcfg->plugin);
  457. bcfg->isDefault = ptree->getPropBool("@defaultBinding", false);
  458. StringBuffer addr;
  459. ptree->getProp("@netAddress", addr);
  460. if (strcmp(addr.str(), ".") == 0)
  461. {
  462. // Here we interpret '.' as binding to all interfaces, so convert it to "0.0.0.0"
  463. bcfg->address.append("0.0.0.0");
  464. }
  465. else
  466. {
  467. bcfg->address.append(addr.str());
  468. }
  469. ptree->getProp("@service", bcfg->service_name);
  470. ptree->getProp("@protocol", bcfg->protocol_name);
  471. m_bindings.push_back(bcfg.getClear());
  472. }
  473. }
  474. }
  475. pt_iter->next();
  476. }
  477. pt_iter->Release();
  478. pt_iter=NULL;
  479. }
  480. readSessionDomainsSetting();
  481. if (sdsSessionNeeded && !daliservers.isEmpty() && !isDetachedFromDali() && !m_bindings.empty())
  482. {
  483. ensureSDSSession();
  484. }
  485. }
  486. }
  487. void CEspConfig::sendAlert(int severity, char const * descr, char const * subject) const
  488. {
  489. }
  490. void CEspConfig::initDali(const char *servers)
  491. {
  492. CriticalBlock b(attachcrit);
  493. if (servers!=nullptr && *servers!=0 && !daliClientActive() && !isDetachedFromDali())
  494. {
  495. DBGLOG("Initializing DALI client [servers = %s]", servers);
  496. useDali=true;
  497. // Create server group
  498. Owned<IGroup> serverGroup = createIGroup(servers, DALI_SERVER_PORT);
  499. if (!serverGroup)
  500. throw MakeStringException(0, "Could not instantiate dali IGroup");
  501. // Initialize client process
  502. if (!initClientProcess(serverGroup, DCR_EspServer))
  503. throw MakeStringException(0, "Could not initialize dali client");
  504. serverstatus = new CSDSServerStatus("ESPserver");
  505. //When esp is starting, the initDali() is called before m_bindings is set.
  506. //We should not call ensureSDSSession() at that time.
  507. if (sdsSessionNeeded && !sdsSessionEnsured && !m_bindings.empty())
  508. ensureSDSSession();
  509. // for auditing
  510. startLogMsgParentReceiver();
  511. connectLogMsgManagerToDali();
  512. }
  513. }
  514. void CEspConfig::initPtree(const char *location, bool isDali)
  515. {
  516. IPropertyTree* cfg = createPTreeFromXMLFile(location, ipt_caseInsensitive);
  517. if (cfg)
  518. {
  519. cfg->addProp("@config", location);
  520. m_envpt.setown(cfg);
  521. }
  522. }
  523. void CEspConfig::loadBinding(binding_cfg &xcfg)
  524. {
  525. map<string, srv_cfg*>::iterator sit = m_services.find(xcfg.service_name.str());
  526. map<string, protocol_cfg*>::iterator pit = m_protocols.find(xcfg.protocol_name.str());
  527. IEspService *isrv = NULL;
  528. IEspProtocol *iprot = NULL;
  529. if(sit == m_services.end())
  530. {
  531. OWARNLOG("Warning: Service %s not found for binding %s", xcfg.service_name.str(), xcfg.name.str());
  532. }
  533. else
  534. {
  535. isrv = (*sit).second->srv;
  536. }
  537. if(pit == m_protocols.end())
  538. {
  539. throw MakeStringException(-1, "Protocol %s not found for binding %s", xcfg.protocol_name.str(), xcfg.name.str());
  540. }
  541. else
  542. {
  543. iprot = (*pit).second->prot;
  544. if (iprot)
  545. {
  546. esp_binding_factory_t xproc = NULL;
  547. if(isrv != NULL)
  548. xcfg.service.setown(LINK(isrv));
  549. xcfg.protocol.setown(LINK(iprot));
  550. builtin *pdirect = getBuiltIn(xcfg.plugin.str());
  551. if (pdirect)
  552. {
  553. xproc = pdirect->bind;
  554. }
  555. else
  556. {
  557. Owned<IEspPlugin> pplg = getPlugin(xcfg.plugin.str());
  558. if (pplg)
  559. {
  560. xproc = (esp_binding_factory_t) pplg->getProcAddress("esp_binding_factory");
  561. }
  562. }
  563. if (xproc)
  564. {
  565. IEspRpcBinding* bind = xproc(xcfg.name.str(), xcfg.type.str(), m_envpt.get(), m_process.str());
  566. if (bind)
  567. LOG(MCoperatorInfo, unknownJob,"Load binding %s (type: %s, process: %s) succeeded", xcfg.name.str(), xcfg.type.str(), m_process.str());
  568. else
  569. OERRLOG("Failed to load binding %s (type: %s, process: %s)", xcfg.name.str(), xcfg.type.str(), m_process.str());
  570. xcfg.bind.setown(bind);
  571. if (serverstatus)
  572. {
  573. IPropertyTree *stTree= serverstatus->queryProperties()->addPropTree("ESPservice", createPTree("ESPservice", ipt_caseInsensitive));
  574. if (stTree)
  575. {
  576. stTree->setProp("@type", xcfg.service->getServiceType());
  577. stTree->setProp("@name", xcfg.service_name.str());
  578. stTree->setPropInt("@port", xcfg.port);
  579. }
  580. serverstatus->commitProperties();
  581. }
  582. }
  583. else
  584. throw MakeStringException(-1, "procedure esp_binding_factory can't be loaded");
  585. }
  586. else
  587. {
  588. throw MakeStringException(-1, "Protocol %s wasn't loaded correctly for the binding", xcfg.protocol_name.str());
  589. }
  590. }
  591. }
  592. void CEspConfig::loadProtocol(protocol_cfg &xcfg)
  593. {
  594. esp_protocol_factory_t xproc = NULL;
  595. builtin *pdirect = getBuiltIn(xcfg.plugin.str());
  596. if (pdirect)
  597. xproc = pdirect->prot;
  598. else
  599. {
  600. Owned<IEspPlugin> pplg = getPlugin(xcfg.plugin.str());
  601. if (pplg)
  602. {
  603. xproc = (esp_protocol_factory_t) pplg->getProcAddress("esp_protocol_factory");
  604. }
  605. }
  606. if (xproc)
  607. {
  608. xcfg.prot.setown(xproc(xcfg.name.str(), xcfg.type.str(), m_envpt.get(), m_process.str()));
  609. if (xcfg.prot)
  610. xcfg.prot->init(m_envpt.get(), m_process.str(), xcfg.name.str());
  611. }
  612. else
  613. throw MakeStringException(-1, "procedure esp_protocol_factory can't be loaded");
  614. }
  615. void CEspConfig::loadService(srv_cfg &xcfg)
  616. {
  617. esp_service_factory_t xproc = NULL;
  618. builtin *pdirect = getBuiltIn(xcfg.plugin.str());
  619. if (pdirect)
  620. xproc = pdirect->serv;
  621. else
  622. {
  623. Owned<IEspPlugin> pplg = getPlugin(xcfg.plugin.str());
  624. if (pplg)
  625. xproc = (esp_service_factory_t) pplg->getProcAddress("esp_service_factory");
  626. }
  627. if (xproc)
  628. xcfg.srv.setown(xproc(xcfg.name.str(), xcfg.type.str(), m_envpt.get(), m_process.str()));
  629. else
  630. throw MakeStringException(-1, "procedure esp_service_factory can't be loaded from %s", xcfg.plugin.str());
  631. }
  632. void CEspConfig::loadServices()
  633. {
  634. map<string, srv_cfg*>::iterator iter = m_services.begin();
  635. while (iter!=m_services.end())
  636. {
  637. #ifndef _USE_OPENLDAP
  638. const string svcName = iter->first;
  639. if (!strstr(svcName.data(), "ws_access"))
  640. #endif
  641. loadService(*(iter->second));
  642. #ifndef _USE_OPENLDAP
  643. else
  644. DBGLOG("Not loading service %s, platform built without LDAP", svcName.data());
  645. #endif
  646. iter++;
  647. }
  648. }
  649. void CEspConfig::loadProtocols()
  650. {
  651. map<string, protocol_cfg*>::iterator iter = m_protocols.begin();
  652. while (iter!=m_protocols.end())
  653. {
  654. loadProtocol(*(iter->second));
  655. iter++;
  656. }
  657. }
  658. void CEspConfig::loadBindings()
  659. {
  660. list<binding_cfg*>::iterator iter = m_bindings.begin();
  661. while (iter!=m_bindings.end())
  662. {
  663. #ifndef _USE_OPENLDAP
  664. const char * bindingName = (**iter).name.str();
  665. if (!strstr(bindingName, "ws_access"))
  666. #endif
  667. loadBinding(**iter);
  668. #ifndef _USE_OPENLDAP
  669. else
  670. DBGLOG("Not binding %s, platform built without LDAP", bindingName);
  671. #endif
  672. iter++;
  673. }
  674. }
  675. void CEspConfig::startEsdlMonitor()
  676. {
  677. start_esdl_monitor_t xproc = nullptr;
  678. Owned<IEspPlugin> pplg = getPlugin("esdl_svc_engine");
  679. if (pplg)
  680. {
  681. DBGLOG("Plugin esdl_svc_engine loaded.");
  682. xproc = (start_esdl_monitor_t) pplg->getProcAddress("startEsdlMonitor");
  683. }
  684. else
  685. throw MakeStringException(-1, "Plugin esdl_svc_engine can't be loaded");
  686. if (xproc)
  687. {
  688. DBGLOG("Procedure startEsdlMonitor loaded, now calling it...");
  689. xproc();
  690. }
  691. else
  692. throw MakeStringException(-1, "procedure startEsdlMonitor can't be loaded");
  693. }
  694. void CEspConfig::stopEsdlMonitor()
  695. {
  696. stop_esdl_monitor_t xproc = nullptr;
  697. Owned<IEspPlugin> pplg = getPlugin("esdl_svc_engine");
  698. if (pplg)
  699. xproc = (stop_esdl_monitor_t) pplg->getProcAddress("stopEsdlMonitor");
  700. if (xproc)
  701. xproc();
  702. }
  703. class ESPxsltIncludeHandler : public CInterface, implements IIncludeHandler
  704. {
  705. public:
  706. // IMPLEMENT_IINTERFACE;
  707. virtual void Link() const
  708. {
  709. CInterface::Link();
  710. }
  711. virtual bool Release() const
  712. {
  713. return CInterface::Release();
  714. }
  715. ESPxsltIncludeHandler()
  716. {
  717. }
  718. ~ESPxsltIncludeHandler()
  719. {
  720. }
  721. inline bool fileExists(StringBuffer &filename)
  722. {
  723. return (checkFileExists(filename.str()) || checkFileExists(filename.toUpperCase().str()) || checkFileExists(filename.toLowerCase().str()));
  724. }
  725. inline bool fileRead(const char *filename, MemoryBuffer &buff)
  726. {
  727. Owned<IFile> fi=createIFile(filename);
  728. if (fi)
  729. {
  730. Owned<IFileIO> fio=fi->open(IFOread);
  731. if (fio)
  732. {
  733. offset_t len=fio->size();
  734. size32_t memlen = (size32_t)len;
  735. assertex(len == memlen);
  736. if (fio->read(0, memlen, buff.reserveTruncate(memlen))==len)
  737. return true;
  738. }
  739. }
  740. buff.clear();
  741. return false;
  742. }
  743. const char *pastLast(const char *src, const char *fnd)
  744. {
  745. int fndlen=(fnd) ? strlen(fnd) : 0;
  746. int srclen=(src) ? strlen(src) : 0;
  747. if (fndlen && srclen)
  748. {
  749. while (srclen--)
  750. {
  751. if (!strnicmp(src+srclen, fnd, fndlen))
  752. return src+srclen+fndlen;
  753. }
  754. }
  755. return NULL;
  756. }
  757. //IIncludeHandler
  758. bool getInclude(const char* includename, MemoryBuffer& includebuf, bool& pathOnly)
  759. {
  760. if(!includename)
  761. return false;
  762. pathOnly = true;
  763. includebuf.clear();
  764. const char *finger=pastLast(includename, "esp/xslt/");
  765. if (finger)
  766. {
  767. StringBuffer filepath;
  768. if (fileExists(filepath.append(getCFD()).append("smc_xslt/").append(finger)) || fileExists(filepath.clear().append(getCFD()).append("xslt/").append(finger)))
  769. {
  770. includebuf.append(filepath.length(), filepath.str());
  771. return true;
  772. }
  773. }
  774. else
  775. {
  776. // First of all, it's better to use absolute path to specify the include, like /esp/xslt/ui_overrides.xslt.
  777. // When you specify the include as relative path, for example ./ui_overrides.xslt
  778. // the path will be expanded (by xmllib's source resolver) to its full path, beginning with file://
  779. // on windows it looks like: file:///C:/playground/esp_lsb2/xslt/ui_overrides.xslt
  780. // on linux: file:///home/yma/playground/esp_lsb2/xslt/ui_overrides.xslt
  781. // If current path not found, use root
  782. char dir[_MAX_PATH];
  783. if (!GetCurrentDirectory(sizeof(dir), dir)) {
  784. IERRLOG("ESPxsltIncludeHandler::getInclude: Current directory path too big, setting local path to null");
  785. dir[0] = 0;
  786. }
  787. #ifdef _WIN32
  788. for(int i = 0; i < _MAX_PATH; i++)
  789. {
  790. if(dir[i] == '\0')
  791. break;
  792. else if(dir[i] == PATHSEPCHAR)
  793. dir[i] = '/';
  794. }
  795. #endif
  796. finger = strstr(includename, dir);
  797. if(finger)
  798. {
  799. finger += strlen(dir) + 1;
  800. StringBuffer filepath(finger);
  801. if (fileExists(filepath))
  802. {
  803. includebuf.append(filepath.length(), filepath.str());
  804. return true;
  805. }
  806. }
  807. }
  808. return false;
  809. }
  810. };
  811. ESPxsltIncludeHandler g_includeHandler;
  812. void CEspConfig::bindServer(IEspServer &server, IEspContainer &container)
  813. {
  814. list<binding_cfg*>::iterator bit = m_bindings.begin();
  815. while (bit != m_bindings.end())
  816. {
  817. binding_cfg *pbfg = *bit;
  818. if (pbfg && pbfg->bind && pbfg->service && pbfg->protocol)
  819. {
  820. map<string, protocol_cfg*>::iterator pit = m_protocols.find(pbfg->protocol_name.str());
  821. if(pit == m_protocols.end())
  822. OWARNLOG("Protocol %s not found for binding %s", pbfg->protocol_name.str(), pbfg->name.str());
  823. else
  824. {
  825. Owned<IXslProcessor> xslp=getXslProcessor();
  826. if (xslp)
  827. {
  828. xslp->setDefIncludeHandler(dynamic_cast<IIncludeHandler*>(&g_includeHandler));
  829. pbfg->bind->setXslProcessor(xslp);
  830. }
  831. pbfg->bind->setContainer(&container);
  832. pbfg->service->setContainer(&container);
  833. pbfg->protocol->setContainer(&container);
  834. pbfg->bind->addProtocol(pbfg->protocol->getProtocolName(), *pbfg->protocol.get());
  835. if(pbfg->service != NULL)
  836. pbfg->bind->addService(pbfg->service->getServiceType(), pbfg->address.str(), pbfg->port, *pbfg->service.get());
  837. IEspProtocol* prot = (*pit).second->prot;
  838. server.addBinding(pbfg->name.str(), pbfg->address.str(), pbfg->port, *prot, *(pbfg->bind.get()), pbfg->isDefault, m_cfg.get());
  839. }
  840. }
  841. else
  842. {
  843. OERRLOG("Binding %s wasn't loaded correctly", pbfg->name.str());
  844. }
  845. bit++;
  846. }
  847. }
  848. void CEspConfig::saveAttachState()
  849. {
  850. StringBuffer espProcAttachState;
  851. espProcAttachState.setf( "<ESPAttachState StateSaveTimems='%d' attached='%s' subscribed='%s'/>", msTick(), isDetachedFromDali() ? "0" : "1", isSubscribedToDali() ? "1" : "0");
  852. DBGLOG("ESP Process [%s] State to be stored: '%s'", m_process.str(), espProcAttachState.str());
  853. Owned<IPropertyTree> serviceESDLDef = createPTreeFromXMLString(espProcAttachState.str(), ipt_caseInsensitive);
  854. saveXML(m_daliAttachStateFileName.str(), serviceESDLDef);
  855. }
  856. void CEspConfig::unloadBindings()
  857. {
  858. list<binding_cfg*>::iterator iter = m_bindings.begin();
  859. while (iter!=m_bindings.end())
  860. {
  861. binding_cfg *bcfg = *iter;
  862. if(bcfg!=NULL)
  863. {
  864. bcfg->protocol.clear();
  865. bcfg->bind.clear();
  866. bcfg->service.clear();
  867. delete bcfg;
  868. }
  869. iter++;
  870. }
  871. m_bindings.clear();
  872. }
  873. void CEspConfig::unloadServices()
  874. {
  875. map<string, srv_cfg*>::iterator srvi = m_services.begin();
  876. while (srvi!=m_services.end())
  877. {
  878. srv_cfg* scfg = srvi->second;
  879. if(scfg)
  880. {
  881. scfg->cfg.clear();
  882. scfg->srv.clear();
  883. delete scfg;
  884. }
  885. srvi++;
  886. }
  887. m_services.clear();
  888. }
  889. void CEspConfig::unloadProtocols()
  890. {
  891. map<string, protocol_cfg*>::iterator proti = m_protocols.begin();
  892. while (proti!=m_protocols.end())
  893. {
  894. protocol_cfg *pcfg = proti->second;
  895. if(pcfg)
  896. {
  897. pcfg->prot.clear();
  898. pcfg->cfg.clear();
  899. delete pcfg;
  900. }
  901. proti++;
  902. }
  903. m_protocols.clear();
  904. }
  905. IEspPlugin* CEspConfig::getPlugin(const char* name)
  906. {
  907. if(!name || !*name)
  908. return NULL;
  909. ForEachItemIn(x, m_plugins)
  910. {
  911. IEspPlugin* plgn = &m_plugins.item(x);
  912. if(plgn && stricmp(name, plgn->getName()) == 0)
  913. {
  914. return LINK(plgn);
  915. }
  916. }
  917. Owned<IEspPlugin> pplg = loadPlugin(name);
  918. if(pplg)
  919. {
  920. pplg->Link(); //YMA: intentional leak. Unloading DLLs during ESP shutdown causes all kinds of issues.
  921. m_plugins.append(*LINK(pplg));
  922. return LINK(pplg);
  923. }
  924. return NULL;
  925. }
  926. void CEspConfig::checkESPCache(IEspServer& server)
  927. {
  928. const char* cacheInitString = m_cfg->queryProp("@espCacheInitString");
  929. IPropertyTree* espCacheCfg = m_cfg->queryBranch("ESPCache");
  930. if (!espCacheCfg && isEmptyString(cacheInitString))
  931. return;
  932. if (!espCacheCfg)
  933. {
  934. if (!server.addCacheClient("default", cacheInitString))
  935. throw MakeStringException(-1, "Failed in checking ESP cache service using %s", cacheInitString);
  936. return;
  937. }
  938. Owned<IPropertyTreeIterator> iter = espCacheCfg->getElements("Group");
  939. ForEach(*iter)
  940. {
  941. IPropertyTree& espCacheGroup = iter->query();
  942. const char* id = espCacheGroup.queryProp("@id");
  943. const char* initString = espCacheGroup.queryProp("@initString");
  944. if (isEmptyString(id))
  945. throw MakeStringException(-1, "ESP cache ID not defined");
  946. if (isEmptyString(initString))
  947. throw MakeStringException(-1, "ESP cache initStrings not defined");
  948. if (!server.addCacheClient(id, initString))
  949. throw MakeStringException(-1, "Failed in checking ESP cache service using %s", initString);
  950. }
  951. }
  952. bool CEspConfig::reSubscribeESPToDali()
  953. {
  954. list<binding_cfg*>::iterator iter = m_bindings.begin();
  955. while (iter!=m_bindings.end())
  956. {
  957. binding_cfg& bindingConfig = **iter;
  958. if (bindingConfig.bind)
  959. {
  960. ESPLOG(LogMin, "Requesting binding '%s' to subscribe to DALI notifications", bindingConfig.name.str());
  961. bindingConfig.bind->subscribeBindingToDali();
  962. }
  963. iter++;
  964. }
  965. setIsSubscribedToDali(true);
  966. return true;
  967. }
  968. bool CEspConfig::unsubscribeESPFromDali()
  969. {
  970. list<binding_cfg*>::iterator iter = m_bindings.begin();
  971. while (iter!=m_bindings.end())
  972. {
  973. binding_cfg& bindingConfig = **iter;
  974. if (bindingConfig.bind)
  975. {
  976. ESPLOG(LogMin, "Requesting binding '%s' to un-subscribe from DALI notifications", bindingConfig.name.str());
  977. bindingConfig.bind->unsubscribeBindingFromDali();
  978. }
  979. iter++;
  980. }
  981. setIsSubscribedToDali(false);
  982. return true;
  983. }
  984. bool CEspConfig::detachESPFromDali(bool force)
  985. {
  986. CriticalBlock b(attachcrit);
  987. if (!isDetachedFromDali())
  988. {
  989. if(!force)
  990. {
  991. if (!canAllBindingsDetachFromDali())
  992. return false;
  993. }
  994. if (!unsubscribeESPFromDali())
  995. return false;
  996. list<binding_cfg*>::iterator iter = m_bindings.begin();
  997. while (iter!=m_bindings.end())
  998. {
  999. binding_cfg& xcfg = **iter;
  1000. ESPLOG(LogMin, "Detach ESP From DALI: requesting binding: '%s' to detach...", xcfg.name.str());
  1001. if (xcfg.bind)
  1002. {
  1003. xcfg.bind->detachBindingFromDali();
  1004. }
  1005. iter++;
  1006. }
  1007. setIsDetachedFromDali(true);
  1008. disconnectLogMsgManagerFromDali();
  1009. closedownClientProcess();
  1010. saveAttachState();
  1011. }
  1012. return true;
  1013. }
  1014. bool CEspConfig::attachESPToDali()
  1015. {
  1016. bool success = true;
  1017. CriticalBlock b(attachcrit);
  1018. if (isDetachedFromDali())
  1019. {
  1020. setIsDetachedFromDali(false);
  1021. StringBuffer daliservers;
  1022. if (m_cfg->getProp("@daliServers", daliservers))
  1023. initDali(daliservers.str());
  1024. list<binding_cfg*>::iterator iter = m_bindings.begin();
  1025. while (iter!=m_bindings.end())
  1026. {
  1027. binding_cfg& xcfg = **iter;
  1028. ESPLOG(LogMin, "Attach ESP to DALI: requesting binding: '%s' to attach...", xcfg.name.str());
  1029. if (xcfg.bind)
  1030. {
  1031. map<string, srv_cfg*>::iterator sit = m_services.find(xcfg.service_name.str());
  1032. if(sit == m_services.end())
  1033. ESPLOG(LogMin, "Warning: Service %s not found for the binding", xcfg.service_name.str());
  1034. else
  1035. ((*sit).second->srv)->attachServiceToDali();
  1036. }
  1037. iter++;
  1038. }
  1039. reSubscribeESPToDali();
  1040. saveAttachState();
  1041. }
  1042. return success;
  1043. }
  1044. bool CEspConfig::canAllBindingsDetachFromDali()
  1045. {
  1046. list<binding_cfg*>::iterator iter = m_bindings.begin();
  1047. while (iter!=m_bindings.end())
  1048. {
  1049. binding_cfg& xcfg = **iter;
  1050. if (!xcfg.bind->canDetachFromDali())
  1051. return false;
  1052. iter++;
  1053. }
  1054. return true;
  1055. }
  1056. IEspRpcBinding* CEspConfig::queryBinding(const char* name)
  1057. {
  1058. for (auto binding : m_bindings)
  1059. {
  1060. if (strcmp(binding->name.str(), name) == 0)
  1061. return binding->bind.get();
  1062. }
  1063. return nullptr;
  1064. }