espcfg.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  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 "espcontext.hpp"
  28. #include <dalienv.hpp>
  29. /*
  30. #if defined(USING_MPATROL)
  31. #define ESP_BUILTIN
  32. #endif
  33. */
  34. //#define ESP_BUILTIN
  35. extern "C" {
  36. ESP_FACTORY IEspService * esp_service_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process);
  37. ESP_FACTORY IEspRpcBinding * esp_binding_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process);
  38. ESP_FACTORY IEspProtocol * esp_protocol_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process);
  39. };
  40. #ifdef ESP_BUILTIN
  41. builtin espdirect;
  42. #endif
  43. // add suffix and prefix when necessary
  44. void fixPlugin(StringBuffer& plugin)
  45. {
  46. if (stricmp(plugin.str()+plugin.length()-sizeof(SharedObjectExtension)+1,SharedObjectExtension)==0)
  47. return;
  48. plugin.insert(0,SharedObjectPrefix);
  49. plugin.append(SharedObjectExtension);
  50. }
  51. void CEspConfig::loadBuiltIns()
  52. {
  53. #ifdef ESP_BUILTIN
  54. espdirect.prot = esp_protocol_factory;
  55. espdirect.bind = esp_binding_factory;
  56. espdirect.serv = esp_service_factory;
  57. #endif
  58. }
  59. builtin *CEspConfig::getBuiltIn(string name)
  60. {
  61. #ifdef ESP_BUILTIN
  62. //if (name.compare("pixall.dll")==0 || name.compare("pixall.so")==0)
  63. return &espdirect;
  64. #else //ESP_DIRECT
  65. return NULL;
  66. #endif
  67. }
  68. StringBuffer &CVSBuildToEspVersion(char const * tag, StringBuffer & out)
  69. {
  70. unsigned build = 0;
  71. unsigned subbuild = 0;
  72. while(!isdigit(*tag))
  73. {
  74. if(!*tag) break;
  75. tag++;
  76. }
  77. while(isdigit(*tag))
  78. {
  79. if(!*tag) break;
  80. build = 10*build + (*tag-'0');
  81. tag++;
  82. }
  83. if(isalpha(*tag))
  84. {
  85. if(islower(*tag))
  86. subbuild = *tag-'a'+1;
  87. else
  88. subbuild = *tag-'A'+1;
  89. }
  90. out.append(build/10).append('.').append(build%10).append(subbuild);
  91. return out;
  92. }
  93. CEspConfig::CEspConfig(IProperties* inputs, IPropertyTree* envpt, IPropertyTree* procpt, bool isDali)
  94. {
  95. hsami_=0;
  96. serverstatus=NULL;
  97. useDali=false;
  98. if(inputs)
  99. m_inputs.setown(inputs);
  100. if(!envpt || !procpt)
  101. return;
  102. m_envpt.setown(envpt);
  103. m_cfg.setown(procpt);
  104. loadBuiltIns();
  105. // load options
  106. const char* level = m_cfg->queryProp("@logLevel");
  107. m_options.logLevel = level ? atoi(level) : LogMin;
  108. m_options.logReq = m_cfg->getPropBool("@logRequests", true);
  109. m_options.logResp = m_cfg->getPropBool("@logResponses", false);
  110. m_options.txSummaryLevel = m_cfg->getPropInt("@txSummaryLevel", LogMin);
  111. m_options.txSummaryResourceReq = m_cfg->getPropBool("@txSummaryResourceReq", false);
  112. m_options.frameTitle.set(m_cfg->queryProp("@name"));
  113. m_options.slowProcessingTime = m_cfg->getPropInt("@slowProcessingTime", 30) * 1000; //in msec
  114. if (!m_cfg->getProp("@name", m_process))
  115. {
  116. ERRLOG("EspProcess name not found");
  117. }
  118. else
  119. {
  120. DBGLOG("ESP process name [%s]", m_process.str());
  121. IPropertyTreeIterator *pt_iter = NULL;
  122. StringBuffer daliservers;
  123. if (m_cfg->getProp("@daliServers", daliservers))
  124. initDali(daliservers.str());
  125. #ifndef _DEBUG
  126. startPerformanceMonitor(m_cfg->getPropInt("@perfReportDelay", 60)*1000);
  127. #endif
  128. //get the local computer name:
  129. m_cfg->getProp("@computer", m_computer);
  130. //get the local computer information:
  131. StringBuffer xpath;
  132. xpath.appendf("Hardware/Computer[@name=\"%s\"]", m_computer.str());
  133. IPropertyTree *computer = m_envpt->queryPropTree(xpath.str());
  134. if (computer)
  135. {
  136. StringBuffer address;
  137. computer->getProp("@netAddress", address);
  138. int port = m_cfg->getPropInt("@port", 1500);
  139. if(strcmp(address.str(), ".") == 0)
  140. {
  141. GetHostName(address.clear());
  142. }
  143. m_address.set(address.str(), (unsigned short) port);
  144. }
  145. xpath.clear();
  146. xpath.append("EspService");
  147. pt_iter = m_cfg->getElements(xpath.str());
  148. if (pt_iter!=NULL)
  149. {
  150. IPropertyTree *ptree = NULL;
  151. pt_iter->first();
  152. while(pt_iter->isValid())
  153. {
  154. ptree = &pt_iter->query();
  155. if (ptree)
  156. {
  157. srv_cfg *svcfg = new srv_cfg;
  158. ptree->getProp("@name", svcfg->name);
  159. ptree->getProp("@type", svcfg->type);
  160. ptree->getProp("@plugin", svcfg->plugin);
  161. fixPlugin(svcfg->plugin);
  162. map<string, srv_cfg*>::value_type en(svcfg->name.str(), svcfg);
  163. m_services.insert(en);
  164. }
  165. pt_iter->next();
  166. }
  167. pt_iter->Release();
  168. pt_iter=NULL;
  169. }
  170. xpath.clear();
  171. xpath.append("EspProtocol");
  172. pt_iter = m_cfg->getElements(xpath.str());
  173. if (pt_iter!=NULL)
  174. {
  175. IPropertyTree *ptree = NULL;
  176. pt_iter->first();
  177. while(pt_iter->isValid())
  178. {
  179. ptree = &pt_iter->query();
  180. if (ptree)
  181. {
  182. protocol_cfg *pcfg = new protocol_cfg;
  183. ptree->getProp("@name", pcfg->name);
  184. ptree->getProp("@plugin", pcfg->plugin);
  185. fixPlugin(pcfg->plugin);
  186. ptree->getProp("@type", pcfg->type);
  187. map<string, protocol_cfg*>::value_type en(pcfg->name.str(), pcfg);
  188. m_protocols.insert(en);
  189. }
  190. pt_iter->next();
  191. }
  192. pt_iter->Release();
  193. pt_iter=NULL;
  194. }
  195. xpath.clear();
  196. xpath.append("EspBinding");
  197. pt_iter = m_cfg->getElements(xpath.str());
  198. if (pt_iter!=NULL)
  199. {
  200. IPropertyTree *ptree = NULL;
  201. pt_iter->first();
  202. while(pt_iter->isValid())
  203. {
  204. ptree = &pt_iter->query();
  205. if (ptree)
  206. {
  207. binding_cfg *bcfg = new binding_cfg;
  208. ptree->getProp("@name", bcfg->name);
  209. ptree->getProp("@type", bcfg->type);
  210. ptree->getProp("@plugin", bcfg->plugin);
  211. fixPlugin(bcfg->plugin);
  212. bcfg->isDefault = ptree->getPropBool("@defaultBinding", false);
  213. StringBuffer addr;
  214. ptree->getProp("@netAddress", addr);
  215. if(strcmp(addr.str(), ".") == 0)
  216. {
  217. bcfg->address.append("0.0.0.0");
  218. }
  219. else
  220. {
  221. bcfg->address.append(addr.str());
  222. }
  223. StringBuffer portstr;
  224. ptree->getProp("@port", portstr);
  225. bcfg->port = atoi(portstr.str());
  226. ptree->getProp("@service", bcfg->service_name);
  227. ptree->getProp("@protocol", bcfg->protocol_name);
  228. m_bindings.push_back(bcfg);
  229. }
  230. pt_iter->next();
  231. }
  232. pt_iter->Release();
  233. pt_iter=NULL;
  234. }
  235. }
  236. }
  237. void CEspConfig::sendAlert(int severity, char const * descr, char const * subject) const
  238. {
  239. }
  240. void CEspConfig::initDali(const char *servers)
  241. {
  242. if (servers!=NULL && *servers!=0 && !daliClientActive())
  243. {
  244. DBGLOG("Initializing DALI client [servers = %s]", servers);
  245. useDali=true;
  246. // Create server group
  247. Owned<IGroup> serverGroup = createIGroup(servers, DALI_SERVER_PORT);
  248. if (!serverGroup)
  249. throw MakeStringException(0, "Could not instantiate dali IGroup");
  250. // Initialize client process
  251. if (!initClientProcess(serverGroup, DCR_EspServer))
  252. throw MakeStringException(0, "Could not initialize dali client");
  253. setPasswordsFromSDS();
  254. serverstatus = new CSDSServerStatus("ESPserver");
  255. }
  256. }
  257. void CEspConfig::initPtree(const char *location, bool isDali)
  258. {
  259. IPropertyTree* cfg = createPTreeFromXMLFile(location, ipt_caseInsensitive);
  260. if (cfg)
  261. {
  262. cfg->addProp("@config", location);
  263. m_envpt.setown(cfg);
  264. }
  265. }
  266. void CEspConfig::loadBinding(binding_cfg &xcfg)
  267. {
  268. map<string, srv_cfg*>::iterator sit = m_services.find(xcfg.service_name.str());
  269. map<string, protocol_cfg*>::iterator pit = m_protocols.find(xcfg.protocol_name.str());
  270. IEspService *isrv = NULL;
  271. IEspProtocol *iprot = NULL;
  272. if(sit == m_services.end())
  273. {
  274. DBGLOG("Warning: Service %s not found for the binding", xcfg.service_name.str());
  275. }
  276. else
  277. {
  278. isrv = (*sit).second->srv;
  279. }
  280. if(pit == m_protocols.end())
  281. {
  282. throw MakeStringException(-1, "Protocol %s not found for the binding", xcfg.protocol_name.str());
  283. }
  284. else
  285. {
  286. iprot = (*pit).second->prot;
  287. if (iprot)
  288. {
  289. esp_binding_factory_t xproc = NULL;
  290. if(isrv != NULL)
  291. xcfg.service.setown(LINK(isrv));
  292. xcfg.protocol.setown(LINK(iprot));
  293. builtin *pdirect = getBuiltIn(xcfg.plugin.str());
  294. if (pdirect)
  295. {
  296. xproc = pdirect->bind;
  297. }
  298. else
  299. {
  300. Owned<IEspPlugin> pplg = getPlugin(xcfg.plugin.str());
  301. if (pplg)
  302. {
  303. xproc = (esp_binding_factory_t) pplg->getProcAddress("esp_binding_factory");
  304. }
  305. }
  306. if (xproc)
  307. {
  308. IEspRpcBinding* bind = xproc(xcfg.name.str(), xcfg.type.str(), m_envpt.get(), m_process.str());
  309. if (bind)
  310. DBGLOG("Load binding %s (type: %s, process: %s) succeeded", xcfg.name.str(), xcfg.type.str(), m_process.str());
  311. else
  312. ERRLOG("Failed to load binding %s (type: %s, process: %s)", xcfg.name.str(), xcfg.type.str(), m_process.str());
  313. xcfg.bind.setown(bind);
  314. if (serverstatus)
  315. {
  316. IPropertyTree *stTree= serverstatus->queryProperties()->addPropTree("ESPservice", createPTree("ESPservice", ipt_caseInsensitive));
  317. if (stTree)
  318. {
  319. stTree->setProp("@type", xcfg.service->getServiceType());
  320. stTree->setProp("@name", xcfg.service_name.str());
  321. stTree->setPropInt("@port", xcfg.port);
  322. }
  323. serverstatus->commitProperties();
  324. }
  325. }
  326. else
  327. throw MakeStringException(-1, "procedure esp_binding_factory can't be loaded");
  328. }
  329. else
  330. {
  331. throw MakeStringException(-1, "Protocol %s wasn't loaded correctly for the binding", xcfg.protocol_name.str());
  332. }
  333. }
  334. }
  335. void CEspConfig::loadProtocol(protocol_cfg &xcfg)
  336. {
  337. esp_protocol_factory_t xproc = NULL;
  338. builtin *pdirect = getBuiltIn(xcfg.plugin.str());
  339. if (pdirect)
  340. xproc = pdirect->prot;
  341. else
  342. {
  343. Owned<IEspPlugin> pplg = getPlugin(xcfg.plugin.str());
  344. if (pplg)
  345. {
  346. xproc = (esp_protocol_factory_t) pplg->getProcAddress("esp_protocol_factory");
  347. }
  348. }
  349. if (xproc)
  350. {
  351. xcfg.prot.setown(xproc(xcfg.name.str(), xcfg.type.str(), m_envpt.get(), m_process.str()));
  352. if (xcfg.prot)
  353. xcfg.prot->init(m_envpt.get(), m_process.str(), xcfg.name.str());
  354. }
  355. else
  356. throw MakeStringException(-1, "procedure esp_protocol_factory can't be loaded");
  357. }
  358. void CEspConfig::loadService(srv_cfg &xcfg)
  359. {
  360. esp_service_factory_t xproc = NULL;
  361. builtin *pdirect = getBuiltIn(xcfg.plugin.str());
  362. if (pdirect)
  363. xproc = pdirect->serv;
  364. else
  365. {
  366. Owned<IEspPlugin> pplg = getPlugin(xcfg.plugin.str());
  367. if (pplg)
  368. xproc = (esp_service_factory_t) pplg->getProcAddress("esp_service_factory");
  369. }
  370. if (xproc)
  371. xcfg.srv.setown(xproc(xcfg.name.str(), xcfg.type.str(), m_envpt.get(), m_process.str()));
  372. else
  373. throw MakeStringException(-1, "procedure esp_service_factory can't be loaded");
  374. }
  375. void CEspConfig::loadServices()
  376. {
  377. map<string, srv_cfg*>::iterator iter = m_services.begin();
  378. while (iter!=m_services.end())
  379. {
  380. loadService(*(iter->second));
  381. iter++;
  382. }
  383. }
  384. void CEspConfig::loadProtocols()
  385. {
  386. map<string, protocol_cfg*>::iterator iter = m_protocols.begin();
  387. while (iter!=m_protocols.end())
  388. {
  389. loadProtocol(*(iter->second));
  390. iter++;
  391. }
  392. }
  393. void CEspConfig::loadBindings()
  394. {
  395. list<binding_cfg*>::iterator iter = m_bindings.begin();
  396. while (iter!=m_bindings.end())
  397. {
  398. loadBinding(**iter);
  399. iter++;
  400. }
  401. }
  402. class ESPxsltIncludeHandler : public CInterface, implements IIncludeHandler
  403. {
  404. public:
  405. // IMPLEMENT_IINTERFACE;
  406. virtual void Link() const
  407. {
  408. CInterface::Link();
  409. }
  410. virtual bool Release() const
  411. {
  412. return CInterface::Release();
  413. }
  414. ESPxsltIncludeHandler()
  415. {
  416. }
  417. ~ESPxsltIncludeHandler()
  418. {
  419. }
  420. inline bool fileExists(StringBuffer &filename)
  421. {
  422. return (checkFileExists(filename.str()) || checkFileExists(filename.toUpperCase().str()) || checkFileExists(filename.toLowerCase().str()));
  423. }
  424. inline bool fileRead(const char *filename, MemoryBuffer &buff)
  425. {
  426. Owned<IFile> fi=createIFile(filename);
  427. if (fi)
  428. {
  429. Owned<IFileIO> fio=fi->open(IFOread);
  430. if (fio)
  431. {
  432. offset_t len=fio->size();
  433. size32_t memlen = (size32_t)len;
  434. assertex(len == memlen);
  435. if (fio->read(0, memlen, buff.reserveTruncate(memlen))==len)
  436. return true;
  437. }
  438. }
  439. buff.clear();
  440. return false;
  441. }
  442. const char *pastLast(const char *src, const char *fnd)
  443. {
  444. int fndlen=(fnd) ? strlen(fnd) : 0;
  445. int srclen=(src) ? strlen(src) : 0;
  446. if (fndlen && srclen)
  447. {
  448. while (srclen--)
  449. {
  450. if (!strnicmp(src+srclen, fnd, fndlen))
  451. return src+srclen+fndlen;
  452. }
  453. }
  454. return NULL;
  455. }
  456. //IIncludeHandler
  457. bool getInclude(const char* includename, MemoryBuffer& includebuf, bool& pathOnly)
  458. {
  459. if(!includename)
  460. return false;
  461. pathOnly = true;
  462. includebuf.clear();
  463. const char *finger=pastLast(includename, "esp/xslt/");
  464. if (finger)
  465. {
  466. StringBuffer filepath;
  467. if (fileExists(filepath.append(getCFD()).append("smc_xslt/").append(finger)) || fileExists(filepath.clear().append(getCFD()).append("xslt/").append(finger)))
  468. {
  469. includebuf.append(filepath.length(), filepath.str());
  470. return true;
  471. }
  472. }
  473. else
  474. {
  475. // First of all, it's better to use absolute path to specify the include, like /esp/xslt/ui_overrides.xslt.
  476. // When you specify the include as relative path, for example ./ui_overrides.xslt
  477. // the path will be expanded (by xmllib's source resolver) to its full path, beginning with file://
  478. // on windows it looks like: file:///C:/playground/esp_lsb2/xslt/ui_overrides.xslt
  479. // on linux: file:///home/yma/playground/esp_lsb2/xslt/ui_overrides.xslt
  480. // If current path not found, use root
  481. char dir[_MAX_PATH];
  482. if (!GetCurrentDirectory(sizeof(dir), dir)) {
  483. ERRLOG("ESPxsltIncludeHandler::getInclude: Current directory path too big, setting local path to null");
  484. dir[0] = 0;
  485. }
  486. #ifdef _WIN32
  487. for(int i = 0; i < _MAX_PATH; i++)
  488. {
  489. if(dir[i] == '\0')
  490. break;
  491. else if(dir[i] == PATHSEPCHAR)
  492. dir[i] = '/';
  493. }
  494. #endif
  495. finger = strstr(includename, dir);
  496. if(finger)
  497. {
  498. finger += strlen(dir) + 1;
  499. StringBuffer filepath(finger);
  500. if (fileExists(filepath))
  501. {
  502. includebuf.append(filepath.length(), filepath.str());
  503. return true;
  504. }
  505. }
  506. }
  507. return false;
  508. }
  509. };
  510. ESPxsltIncludeHandler g_includeHandler;
  511. void CEspConfig::bindServer(IEspServer &server, IEspContainer &container)
  512. {
  513. list<binding_cfg*>::iterator bit = m_bindings.begin();
  514. while (bit != m_bindings.end())
  515. {
  516. binding_cfg *pbfg = *bit;
  517. if (pbfg && pbfg->bind && pbfg->service && pbfg->protocol)
  518. {
  519. map<string, protocol_cfg*>::iterator pit = m_protocols.find(pbfg->protocol_name.str());
  520. if(pit == m_protocols.end())
  521. DBGLOG("Protocol %s not found for binding %s", pbfg->protocol_name.str(), pbfg->name.str());
  522. else
  523. {
  524. Owned<IXslProcessor> xslp=getXslProcessor();
  525. if (xslp)
  526. {
  527. xslp->setDefIncludeHandler(dynamic_cast<IIncludeHandler*>(&g_includeHandler));
  528. pbfg->bind->setXslProcessor(xslp);
  529. }
  530. pbfg->bind->setContainer(&container);
  531. pbfg->service->setContainer(&container);
  532. pbfg->protocol->setContainer(&container);
  533. pbfg->bind->addProtocol(pbfg->protocol->getProtocolName(), *pbfg->protocol.get());
  534. if(pbfg->service != NULL)
  535. pbfg->bind->addService(pbfg->service->getServiceType(), pbfg->address.str(), pbfg->port, *pbfg->service.get());
  536. IEspProtocol* prot = (*pit).second->prot;
  537. server.addBinding(pbfg->name.str(), pbfg->address.str(), pbfg->port, *prot, *(pbfg->bind.get()), pbfg->isDefault, m_cfg.get());
  538. }
  539. }
  540. else
  541. {
  542. ERRLOG("Binding %s wasn't loaded correctly", pbfg->name.str());
  543. }
  544. bit++;
  545. }
  546. }
  547. void CEspConfig::unloadBindings()
  548. {
  549. list<binding_cfg*>::iterator iter = m_bindings.begin();
  550. while (iter!=m_bindings.end())
  551. {
  552. binding_cfg *bcfg = *iter;
  553. if(bcfg!=NULL)
  554. {
  555. bcfg->protocol.clear();
  556. bcfg->bind.clear();
  557. bcfg->service.clear();
  558. delete bcfg;
  559. }
  560. iter++;
  561. }
  562. m_bindings.clear();
  563. }
  564. void CEspConfig::unloadServices()
  565. {
  566. map<string, srv_cfg*>::iterator srvi = m_services.begin();
  567. while (srvi!=m_services.end())
  568. {
  569. srv_cfg* scfg = srvi->second;
  570. if(scfg)
  571. {
  572. scfg->cfg.clear();
  573. scfg->srv.clear();
  574. delete scfg;
  575. }
  576. srvi++;
  577. }
  578. m_services.clear();
  579. }
  580. void CEspConfig::unloadProtocols()
  581. {
  582. map<string, protocol_cfg*>::iterator proti = m_protocols.begin();
  583. while (proti!=m_protocols.end())
  584. {
  585. protocol_cfg *pcfg = proti->second;
  586. if(pcfg)
  587. {
  588. pcfg->prot.clear();
  589. pcfg->cfg.clear();
  590. delete pcfg;
  591. }
  592. proti++;
  593. }
  594. m_protocols.clear();
  595. }
  596. IEspPlugin* CEspConfig::getPlugin(const char* name)
  597. {
  598. if(!name || !*name)
  599. return NULL;
  600. ForEachItemIn(x, m_plugins)
  601. {
  602. IEspPlugin* plgn = &m_plugins.item(x);
  603. if(plgn && stricmp(name, plgn->getName()) == 0)
  604. {
  605. return LINK(plgn);
  606. }
  607. }
  608. Owned<IEspPlugin> pplg = loadPlugin(name);
  609. if(pplg)
  610. {
  611. pplg->Link(); //YMA: intentional leak. Unloading DLLs during ESP shutdown causes all kinds of issues.
  612. m_plugins.append(*LINK(pplg));
  613. return LINK(pplg);
  614. }
  615. return NULL;
  616. }