dllserver.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  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. #include "jliball.hpp"
  14. #include "dllserver.hpp"
  15. #include "jiter.ipp"
  16. #include "jexcept.hpp"
  17. #include "dllservererr.hpp"
  18. #include "daclient.hpp"
  19. #include "dasds.hpp"
  20. #include "rmtfile.hpp"
  21. #include "dalienv.hpp"
  22. #include "thorplugin.hpp"
  23. #ifdef _WIN32
  24. #define DEFAULT_SERVER_ROOTDIR "c:\\HPCCSystems\\hpcc-data\\temp\\dllserver"
  25. #else
  26. #define DEFAULT_SERVER_ROOTDIR "/var/lib/HPCCSystems/dllserver/temp"
  27. #endif
  28. #define CONNECTION_TIMEOUT 30000
  29. static Owned<IConstDomainInfo> hostDomain;
  30. IConstDomainInfo * getDomainFromIp(const char * ip)
  31. {
  32. Owned<IEnvironmentFactory> ef = getEnvironmentFactory();
  33. Owned<IConstEnvironment> env = ef->openEnvironment();
  34. if (!env)
  35. return NULL;
  36. Owned<IConstMachineInfo> curMachine = env->getMachineByAddress(ip);
  37. if (!curMachine)
  38. return NULL;
  39. return curMachine->getDomain();
  40. }
  41. IConstDomainInfo * cachedHostDomain()
  42. {
  43. if (!hostDomain)
  44. {
  45. StringBuffer ipText;
  46. queryHostIP().getIpText(ipText);
  47. hostDomain.setown(getDomainFromIp(ipText.str()));
  48. }
  49. return hostDomain;
  50. }
  51. static void getMangledTag(StringBuffer & path, const char * name)
  52. {
  53. path.append("Dll");
  54. unsigned len = strlen(name);
  55. path.ensureCapacity(len);
  56. for (unsigned i=0; i < len; i++)
  57. {
  58. char next = name[i];
  59. if (isalnum((byte)next))
  60. path.append(next);
  61. else
  62. path.append("_");
  63. }
  64. }
  65. static void getOldXPath(StringBuffer & path, const char * name)
  66. {
  67. path.append("/GeneratedDlls/GeneratedDll[@uid=\"").append(name).append("\"]");
  68. }
  69. static void getNewXPath(StringBuffer & path, const char * name)
  70. {
  71. path.append("/GeneratedDlls/");
  72. getMangledTag(path, name);
  73. //The following qualifier is here in case two different characters were mapped to _ - creating an ambiguous tag.
  74. path.append("[@name=\"").append(name).append("\"]");
  75. }
  76. IRemoteConnection * getEntryConnection(const char * name, unsigned mode)
  77. {
  78. StringBuffer xpath;
  79. getNewXPath(xpath, name);
  80. Owned<IRemoteConnection> connection = querySDS().connect(xpath.str(), myProcessSession(), mode, CONNECTION_TIMEOUT);
  81. if (connection)
  82. return connection.getClear();
  83. //Retain backwards compatibility for the moment
  84. getOldXPath(xpath.clear(), name);
  85. return querySDS().connect(xpath.str(), myProcessSession(), mode, CONNECTION_TIMEOUT);
  86. }
  87. //---------------------------------------------------------------------------
  88. class TreeIteratorWrapper : implements IIterator, public CInterface
  89. {
  90. public:
  91. TreeIteratorWrapper(IPropertyTreeIterator * _iter) { iter.setown(_iter); }
  92. IMPLEMENT_IINTERFACE
  93. virtual bool first()
  94. {
  95. cur.clear();
  96. return iter->first();
  97. }
  98. virtual bool next()
  99. {
  100. cur.clear();
  101. return iter->next();
  102. }
  103. virtual bool isValid()
  104. {
  105. return (cur != NULL);
  106. }
  107. virtual IInterface & get()
  108. {
  109. return *cur.getLink();
  110. }
  111. virtual IInterface & query()
  112. {
  113. return *cur;
  114. }
  115. protected:
  116. Owned<IInterface> cur;
  117. Owned<IPropertyTreeIterator> iter;
  118. };
  119. //---------------------------------------------------------------------------
  120. static void deleteLocationFiles(IDllLocation & cur, bool removeDirectory)
  121. {
  122. RemoteFilename filename;
  123. cur.getDllFilename(filename);
  124. Owned<IFile> file = createIFile(filename);
  125. file->remove();
  126. if (cur.getLibFilename(filename))
  127. {
  128. file.setown(createIFile(filename));
  129. file->remove();
  130. }
  131. if (removeDirectory)
  132. {
  133. //Finally try and remove the directory - this will fail if it isn't empty
  134. StringBuffer path, dir;
  135. cur.getDllFilename(filename);
  136. filename.getRemotePath(path);
  137. splitDirTail(path.str(), dir);
  138. filename.setRemotePath(dir.str());
  139. file.setown(createIFile(filename));
  140. file->remove();
  141. }
  142. }
  143. class DllLocation : implements IDllLocation, public CInterface
  144. {
  145. StringAttr cacheRoot;
  146. public:
  147. DllLocation(IPropertyTree * _entryRoot, IPropertyTree * _locationRoot, const char *_cacheRoot)
  148. : cacheRoot(_cacheRoot)
  149. {
  150. entryRoot.set(_entryRoot);
  151. locationRoot.set(_locationRoot);
  152. }
  153. IMPLEMENT_IINTERFACE
  154. virtual void getDllFilename(RemoteFilename & filename)
  155. {
  156. SocketEndpoint ep(locationRoot->queryProp("@ip"));
  157. filename.setPath(ep, locationRoot->queryProp("@dll"));
  158. }
  159. virtual bool getLibFilename(RemoteFilename & filename)
  160. {
  161. const char * lib = locationRoot->queryProp("@lib");
  162. if (!lib) return false;
  163. #ifndef _WIN32
  164. int namelen = strlen(lib);
  165. StringBuffer libnamebuf(lib);
  166. if(!((namelen >= 3) && (strcmp(lib+namelen-3, ".so") == 0)))
  167. {
  168. libnamebuf.append(".so");
  169. lib = libnamebuf.str();
  170. }
  171. #endif
  172. SocketEndpoint ep(locationRoot->queryProp("@ip"));
  173. filename.setPath(ep, lib);
  174. return true;
  175. }
  176. virtual void getIP(IpAddress & ip)
  177. {
  178. ip.ipset(locationRoot->queryProp("@ip"));
  179. }
  180. virtual DllLocationType queryLocation()
  181. {
  182. SocketEndpoint ep(locationRoot->queryProp("@ip"));
  183. if (ep.isLocal())
  184. {
  185. RemoteFilename filename;
  186. getDllFilename(filename);
  187. StringBuffer lp;
  188. filename.getLocalPath(lp);
  189. if (strncmp(lp, cacheRoot, strlen(cacheRoot))==0)
  190. return DllLocationDirectory;
  191. return DllLocationLocal;
  192. }
  193. #ifdef _WIN32
  194. Owned<IConstDomainInfo> curDomain = getDomainFromIp(locationRoot->queryProp("@ip"));
  195. IConstDomainInfo * hostDomain = cachedHostDomain();
  196. if (curDomain && hostDomain && (curDomain == hostDomain))
  197. return DllLocationDomain;
  198. #endif
  199. return DllLocationAnywhere;
  200. }
  201. virtual void remove(bool removeFiles, bool removeDirectory);
  202. protected:
  203. Owned<IPropertyTree> locationRoot;
  204. Owned<IPropertyTree> entryRoot;
  205. };
  206. static bool propsMatch(IPropertyTree & left, IPropertyTree & right, const char * prop)
  207. {
  208. const char * l = left.queryProp(prop);
  209. const char * r = right.queryProp(prop);
  210. if (!l || !r) return (l == r);
  211. return strcmp(l, r) == 0;
  212. }
  213. void DllLocation::remove(bool removeFiles, bool removeDirectory)
  214. {
  215. if (removeFiles)
  216. {
  217. try
  218. {
  219. deleteLocationFiles(*this, removeDirectory);
  220. }
  221. catch (IException * e)
  222. {
  223. EXCLOG(e, "Removing dll");
  224. e->Release();
  225. }
  226. }
  227. Owned<IRemoteConnection> conn = getEntryConnection(entryRoot->queryProp("@name"), RTM_LOCK_WRITE);
  228. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements("location");
  229. ForEach(*iter)
  230. {
  231. IPropertyTree & cur = iter->query();
  232. if (propsMatch(cur, *locationRoot, "@ip") && propsMatch(cur, *locationRoot, "@dll") && propsMatch(cur, *locationRoot, "@lib"))
  233. {
  234. conn->queryRoot()->removeTree(&cur);
  235. break;
  236. }
  237. }
  238. }
  239. class LocationIterator : public TreeIteratorWrapper
  240. {
  241. StringAttr cacheRoot;
  242. public:
  243. LocationIterator(IPropertyTree * _dllEntry, IPropertyTreeIterator * _iter, const char *_cacheRoot)
  244. : TreeIteratorWrapper(_iter), cacheRoot(_cacheRoot)
  245. {
  246. dllEntry.set(_dllEntry);
  247. }
  248. virtual bool first()
  249. {
  250. bool ok = TreeIteratorWrapper::first();
  251. if (ok)
  252. cur.setown(new DllLocation(dllEntry, &iter->query(), cacheRoot));
  253. return ok;
  254. }
  255. virtual bool next()
  256. {
  257. bool ok = TreeIteratorWrapper::next();
  258. if (ok)
  259. cur.setown(new DllLocation(dllEntry, &iter->query(), cacheRoot));
  260. return ok;
  261. }
  262. protected:
  263. Owned<IPropertyTree> dllEntry;
  264. };
  265. //---------------------------------------------------------------------------
  266. class DllEntry : implements IDllEntry, public CInterface
  267. {
  268. public:
  269. DllEntry(IPropertyTree *root, const char *cacheRoot, IPropertyTree *owner);
  270. IMPLEMENT_IINTERFACE
  271. virtual IIterator * createLocationIterator();
  272. virtual IDllLocation * getBestLocation();
  273. virtual IDllLocation * getBestLocationCandidate();
  274. virtual void getCreated(IJlibDateTime & dateTime)
  275. {
  276. dateTime.setString(root->queryProp("@created"));
  277. }
  278. virtual const char * queryKind()
  279. {
  280. return root->queryProp("@kind");
  281. }
  282. virtual const char * queryName()
  283. {
  284. return root->queryProp("@name");
  285. }
  286. virtual void remove(bool removeFiles, bool removeDirectory);
  287. protected:
  288. Owned<IPropertyTree> root, owner;
  289. StringAttr cacheRoot;
  290. };
  291. DllEntry::DllEntry(IPropertyTree *_root, const char *_cacheRoot, IPropertyTree *_owner)
  292. : cacheRoot(_cacheRoot)
  293. {
  294. root.set(_root);
  295. owner.set(_owner);
  296. }
  297. IIterator * DllEntry::createLocationIterator()
  298. {
  299. return new LocationIterator(root, root->getElements("location"), cacheRoot);
  300. }
  301. typedef IArrayOf<IDllLocation> LocationArray;
  302. int orderLocations(IInterface * const * pLeft, IInterface * const * pRight)
  303. {
  304. IDllLocation * left = (IDllLocation *)*pLeft;
  305. IDllLocation * right = (IDllLocation *)*pRight;
  306. return right->queryLocation() - left->queryLocation();
  307. }
  308. IDllLocation * DllEntry::getBestLocation()
  309. {
  310. LocationArray locations;
  311. Owned<IIterator> iter = createLocationIterator();
  312. ForEach(*iter)
  313. locations.append((IDllLocation &)iter->get());
  314. locations.sort(orderLocations);
  315. ForEachItemIn(idx, locations)
  316. {
  317. IDllLocation & cur = locations.item(idx);
  318. try
  319. {
  320. RemoteFilename filename;
  321. cur.getDllFilename(filename);
  322. Owned<IFile> file = createIFile(filename);
  323. Owned<IFileIO> io = file->open(IFOread);
  324. if (io)
  325. return LINK(&cur);
  326. }
  327. catch (IException * e)
  328. {
  329. StringBuffer s;
  330. EXCLOG(e, s.appendf("GetBestLocation - could not load entry for %s", root->queryProp("@name")).str());
  331. e->Release();
  332. //MORE: Should possibly remove the entry... but we don't know why we couldn't read it - could be a domain issue.
  333. }
  334. }
  335. throwError1(DSVERR_CouldNotFindDll, root->queryProp("@name"));
  336. return NULL;
  337. }
  338. IDllLocation * DllEntry::getBestLocationCandidate()
  339. {
  340. Owned<IIterator> iter = createLocationIterator();
  341. Owned<IDllLocation> best;
  342. DllLocationType bestLocation = DllLocationNowhere;
  343. ForEach(*iter)
  344. {
  345. IDllLocation & cur = (IDllLocation &)iter->query();
  346. DllLocationType location = cur.queryLocation();
  347. if (location == DllLocationDirectory)
  348. return LINK(&cur);
  349. if (location > bestLocation)
  350. {
  351. best.set(&cur);
  352. bestLocation = location;
  353. }
  354. }
  355. if (!best)
  356. throwError1(DSVERR_CouldNotFindDll, root->queryProp("@name"));
  357. return best.getClear();
  358. }
  359. void DllEntry::remove(bool removeFiles, bool removeDirectory)
  360. {
  361. if (removeFiles)
  362. {
  363. Owned<IIterator> iter = createLocationIterator();
  364. // a bit nasty, but don't remove the directory for the first location, since this is where things are created in the first place.
  365. bool isFirst = true;
  366. ForEach(*iter)
  367. {
  368. try
  369. {
  370. IDllLocation & cur = (IDllLocation &)iter->query();
  371. deleteLocationFiles(cur, removeDirectory && !isFirst);
  372. }
  373. catch (IException * e)
  374. {
  375. EXCLOG(e, "Removing dll");
  376. e->Release();
  377. }
  378. isFirst = false;
  379. }
  380. }
  381. if (owner)
  382. owner->removeTree(root);
  383. else
  384. {
  385. Owned<IRemoteConnection> conn = getEntryConnection(root->queryProp("@name"), RTM_LOCK_WRITE);
  386. conn->close(true);
  387. }
  388. }
  389. class DllIterator : public TreeIteratorWrapper
  390. {
  391. public:
  392. DllIterator(IPropertyTree * _root, IPropertyTreeIterator * _iter, const char *_cacheRoot)
  393. : TreeIteratorWrapper(_iter), cacheRoot(_cacheRoot)
  394. {
  395. root.set(_root);
  396. }
  397. virtual bool first()
  398. {
  399. bool ok = TreeIteratorWrapper::first();
  400. if (ok)
  401. cur.setown(new DllEntry(&iter->query(), cacheRoot, NULL));
  402. return ok;
  403. }
  404. virtual bool next()
  405. {
  406. bool ok = TreeIteratorWrapper::next();
  407. if (ok)
  408. cur.setown(new DllEntry(&iter->query(), cacheRoot, NULL));
  409. return ok;
  410. }
  411. protected:
  412. Owned<IPropertyTree> root;
  413. StringAttr cacheRoot;
  414. };
  415. //---------------------------------------------------------------------------
  416. class DllServer : implements IDllServer, public CInterface
  417. {
  418. public:
  419. DllServer(const char * _rootDir);
  420. IMPLEMENT_IINTERFACE
  421. virtual IIterator * createDllIterator();
  422. virtual void ensureAvailable(const char * name, DllLocationType location);
  423. virtual void getDll(const char * name, MemoryBuffer & dllText);
  424. virtual IDllEntry * getEntry(const char * name);
  425. virtual void getLibrary(const char * name, MemoryBuffer & dllText);
  426. virtual void getLocalLibraryName(const char * name, StringBuffer & libraryName);
  427. virtual DllLocationType isAvailable(const char * name);
  428. virtual ILoadedDllEntry * loadDll(const char * name, DllLocationType location);
  429. virtual void removeDll(const char * name, bool removeDlls, bool removeDirectory);
  430. virtual void registerDll(const char * name, const char * kind, const char * dllPath);
  431. virtual IDllEntry * createEntry(IPropertyTree *owner, IPropertyTree *entry);
  432. protected:
  433. void copyFileLocally(RemoteFilename & targetName, RemoteFilename & sourceName);
  434. DllEntry * doGetEntry(const char * name);
  435. void doRegisterDll(const char * name, const char * kind, const char * dllPath, const char * libPath);
  436. IDllLocation * getBestMatch(const char * name);
  437. IDllLocation * getBestMatchEx(const char * name);
  438. protected:
  439. StringAttr rootDir;
  440. };
  441. DllServer::DllServer(const char * _rootDir)
  442. {
  443. rootDir.set(_rootDir);
  444. }
  445. void DllServer::copyFileLocally(RemoteFilename & targetName, RemoteFilename & sourceName)
  446. {
  447. StringBuffer sourceLocalPath,targetLocalPath;
  448. sourceName.getLocalPath(sourceLocalPath);
  449. targetLocalPath.append(rootDir);
  450. recursiveCreateDirectory(targetLocalPath.str());
  451. addPathSepChar(targetLocalPath);
  452. splitFilename(sourceLocalPath.str(),NULL,NULL,&targetLocalPath,&targetLocalPath);
  453. SocketEndpoint hostEndpoint;
  454. hostEndpoint.setLocalHost((unsigned short)0);
  455. targetName.setPath(hostEndpoint, targetLocalPath.str());
  456. OwnedIFile source = createIFile(sourceName);
  457. OwnedIFile target = createIFile(targetName);
  458. source->copyTo(target, 0, NULL, true);
  459. }
  460. IIterator * DllServer::createDllIterator()
  461. {
  462. Owned<IRemoteConnection> conn = querySDS().connect("/GeneratedDlls", myProcessSession(), 0, CONNECTION_TIMEOUT);
  463. IPropertyTree * root = conn->queryRoot();
  464. return conn ? (IIterator *)new DllIterator(root, root->getElements("*"), rootDir) : (IIterator *)new CNullIterator;
  465. }
  466. DllEntry * DllServer::doGetEntry(const char * name)
  467. {
  468. Owned<IRemoteConnection> conn = getEntryConnection(name, 0);
  469. if (conn)
  470. return new DllEntry(conn->queryRoot(), rootDir, NULL);
  471. return NULL;
  472. }
  473. IDllEntry * DllServer::createEntry(IPropertyTree *owner, IPropertyTree *entry)
  474. {
  475. return new DllEntry(entry, rootDir, owner);
  476. }
  477. void DllServer::doRegisterDll(const char * name, const char * kind, const char * dllPath, const char * libPath)
  478. {
  479. RemoteFilename dllRemote;
  480. StringBuffer ipText, dllText;
  481. dllRemote.setRemotePath(dllPath);
  482. dllRemote.queryIP().getIpText(ipText);
  483. dllRemote.getLocalPath(dllText);
  484. Owned<IRemoteConnection> conn = getEntryConnection(name, RTM_LOCK_WRITE);
  485. if (conn)
  486. {
  487. /* check the entry doesn't exist already....
  488. * Ideally the connection above would be a RTM_LOCK_READ and be changed to a RTM_LOCK_WRITE only when 'location' not found
  489. */
  490. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements("location");
  491. ForEach(*iter)
  492. {
  493. IPropertyTree & cur = iter->query();
  494. if ((stricmp(cur.queryProp("@ip"),ipText.str()) == 0) &&
  495. (stricmp(cur.queryProp("@dll"),dllText.str()) == 0))
  496. return;
  497. }
  498. }
  499. else
  500. {
  501. /* in theory, two clients/threads could get here at the same time
  502. * in practice only one client/thread will be adding a unique named generated dll
  503. */
  504. StringBuffer xpath;
  505. xpath.append("/GeneratedDlls/");
  506. getMangledTag(xpath, name);
  507. conn.setown(querySDS().connect(xpath, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, CONNECTION_TIMEOUT));
  508. assertex(conn); // RTM_CREATE_QUERY will create GeneratedDlls parent node if it doesn't exist.
  509. IPropertyTree * entry = conn->queryRoot();
  510. entry->setProp("@name", name);
  511. entry->setProp("@kind", kind);
  512. Owned<IJlibDateTime> now = createDateTimeNow();
  513. StringBuffer nowText;
  514. StringBufferAdaptor strval(nowText);
  515. now->getString(strval);
  516. entry->setProp("@created", nowText.str());
  517. }
  518. IPropertyTree * locationTree = createPTree("location");
  519. locationTree->setProp("@ip", ipText.str());
  520. locationTree->setProp("@dll", dllText.str());
  521. if (libPath && strlen(libPath))
  522. {
  523. RemoteFilename libRemote;
  524. libRemote.setRemotePath(libPath);
  525. if (!dllRemote.queryIP().ipequals(libRemote.queryIP()))
  526. throwError(DSVERR_DllLibIpMismatch);
  527. StringBuffer libText;
  528. libRemote.getLocalPath(libText);
  529. locationTree->setProp("@lib", libText.str());
  530. }
  531. conn->queryRoot()->addPropTree("location", locationTree);
  532. }
  533. void DllServer::ensureAvailable(const char * name, DllLocationType location)
  534. {
  535. Owned<DllEntry> match = doGetEntry(name);
  536. if (!match)
  537. throwError1(DSVERR_CouldNotFindDll, name);
  538. Owned<IDllLocation> bestLocation = match->getBestLocation();
  539. if (bestLocation->queryLocation() < location)
  540. {
  541. StringBuffer remoteDllPath, remoteLibPath;
  542. RemoteFilename sourceName, dllName, libName;
  543. bestLocation->getDllFilename(sourceName);
  544. copyFileLocally(dllName, sourceName);
  545. dllName.getRemotePath(remoteDllPath);
  546. if (bestLocation->getLibFilename(sourceName))
  547. {
  548. copyFileLocally(libName, sourceName);
  549. libName.getRemotePath(remoteLibPath);
  550. }
  551. doRegisterDll(name, "**Error**", remoteDllPath.str(), remoteLibPath.str());
  552. assertex(isAvailable(name) >= DllLocationLocal);
  553. }
  554. }
  555. IDllLocation * DllServer::getBestMatch(const char * name)
  556. {
  557. Owned<DllEntry> match = doGetEntry(name);
  558. if (!match)
  559. return NULL;
  560. return match->getBestLocation();
  561. }
  562. IDllLocation * DllServer::getBestMatchEx(const char * name)
  563. {
  564. IDllLocation * location = getBestMatch(name);
  565. if (!location)
  566. throwError1(DSVERR_CouldNotFindDll, name);
  567. return location;
  568. }
  569. IDllEntry * DllServer::getEntry(const char * name)
  570. {
  571. return doGetEntry(name);
  572. }
  573. void DllServer::getDll(const char * name, MemoryBuffer & dllText)
  574. {
  575. RemoteFilename filename;
  576. Owned<IDllLocation> match = getBestMatchEx(name);
  577. match->getDllFilename(filename);
  578. Owned<IFile> file = createIFile(filename);
  579. OwnedIFileIO io = file->open(IFOread);
  580. read(io, 0, (size32_t)-1, dllText);
  581. }
  582. void DllServer::getLibrary(const char * name, MemoryBuffer & libText)
  583. {
  584. RemoteFilename filename;
  585. Owned<IDllLocation> match = getBestMatchEx(name);
  586. if (!match->getLibFilename(filename))
  587. throwError1(DSVERR_NoAssociatedLib, name);
  588. Owned<IFile> file = createIFile(filename);
  589. OwnedIFileIO io = file->open(IFOread);
  590. read(io, 0, (size32_t)-1, libText);
  591. }
  592. void DllServer::getLocalLibraryName(const char * name, StringBuffer & libraryName)
  593. {
  594. RemoteFilename filename;
  595. Owned<IDllLocation> match = getBestMatchEx(name);
  596. if (match->queryLocation() < DllLocationLocal)
  597. throwError1(DSVERR_LibNotLocal, name);
  598. if (!match->getLibFilename(filename))
  599. throwError1(DSVERR_NoAssociatedLib, name);
  600. filename.getLocalPath(libraryName);
  601. }
  602. DllLocationType DllServer::isAvailable(const char * name)
  603. {
  604. try
  605. {
  606. Owned<IDllLocation> match = getBestMatch(name);
  607. if (match)
  608. return match->queryLocation();
  609. }
  610. catch (IException *E)
  611. {
  612. E->Release();
  613. }
  614. return DllLocationNowhere;
  615. }
  616. ILoadedDllEntry * DllServer::loadDll(const char * name, DllLocationType type)
  617. {
  618. #ifdef _WIN32
  619. if (type < DllLocationDomain)
  620. type = DllLocationDomain;
  621. #else
  622. if (type < DllLocationLocal)
  623. type = DllLocationLocal;
  624. #endif
  625. ensureAvailable(name, type);
  626. Owned<IDllLocation> location = getBestMatchEx(name);
  627. RemoteFilename rfile;
  628. location->getDllFilename(rfile);
  629. StringBuffer x;
  630. rfile.getPath(x);
  631. LOG(MCdebugInfo, unknownJob, "Loading dll (%s) from location %s", name, x.str());
  632. return createDllEntry(x.str(), false, NULL);
  633. }
  634. void DllServer::removeDll(const char * name, bool removeDlls, bool removeDirectory)
  635. {
  636. Owned<IDllEntry> entry = getEntry(name);
  637. if (entry)
  638. entry->remove(removeDlls, removeDirectory);
  639. }
  640. void DllServer::registerDll(const char * name, const char * kind, const char * dllLocation)
  641. {
  642. doRegisterDll(name, kind, dllLocation, NULL);
  643. }
  644. //---------------------------------------------------------------------------
  645. static DllServer * dllServer;
  646. CriticalSection dllServerCrit;
  647. IDllServer & queryDllServer()
  648. {
  649. CriticalBlock b(dllServerCrit);
  650. if (!dllServer)
  651. {
  652. const char* dllserver_root = getenv("DLLSERVER_ROOT");
  653. StringBuffer dir;
  654. if(dllserver_root == NULL)
  655. {
  656. if (envGetConfigurationDirectory("temp","dllserver","dllserver",dir)) // not sure if different instance might be better but never separated in past
  657. dllserver_root = dir.str();
  658. else
  659. dllserver_root = DEFAULT_SERVER_ROOTDIR;
  660. }
  661. initDllServer(dllserver_root);
  662. }
  663. return *dllServer;
  664. }
  665. void closeDllServer()
  666. {
  667. hostDomain.clear();
  668. if (dllServer)
  669. {
  670. dllServer->Release();
  671. dllServer = NULL;
  672. }
  673. }
  674. void initDllServer(const char * localRoot)
  675. {
  676. CriticalBlock b(dllServerCrit);
  677. ::Release(dllServer);
  678. dllServer = new DllServer(localRoot);
  679. }
  680. void cleanUpOldDlls()
  681. {
  682. Owned<IJlibDateTime> cutoff = createDateTimeNow();
  683. unsigned year;
  684. unsigned month;
  685. unsigned day;
  686. cutoff->getGmtDate(year, month, day);
  687. if (false && month-- == 1)
  688. {
  689. month = 12;
  690. year--;
  691. }
  692. cutoff->setGmtDate(year, month, day);
  693. //Remove all but one copy of all workunits more than a month old
  694. Owned<IIterator> dllIter = queryDllServer().createDllIterator();
  695. ForEach(*dllIter)
  696. {
  697. IDllEntry & entry = (IDllEntry &)dllIter->query();
  698. if (strcmp(entry.queryKind(), "workunit")==0)
  699. {
  700. Owned<IJlibDateTime> created = createDateTime();
  701. entry.getCreated(*created);
  702. if (created->compare(*cutoff) < 0)
  703. {
  704. Owned<IIterator> locIter = entry.createLocationIterator();
  705. bool first = true;
  706. ForEach(*locIter)
  707. {
  708. IDllLocation & location = (IDllLocation &)locIter->query();
  709. if (!first)
  710. location.remove(true, true);
  711. first = false;
  712. }
  713. }
  714. }
  715. }
  716. }
  717. void testDllServer()
  718. {
  719. IDllServer & server = queryDllServer();
  720. Owned<IDllEntry> oldentry2 = server.getEntry("WorkUnit1");
  721. if (oldentry2)
  722. oldentry2->remove(false, false);
  723. server.registerDll("WorkUnit1","workunit","\\\\ghalliday\\c$\\edata\\ecl\\regress\\process0.dll");
  724. assertex(server.isAvailable("WorkUnit1") == DllLocationLocal);
  725. server.ensureAvailable("WorkUnit1",DllLocationLocal);
  726. server.registerDll("WorkUnit1","workunit","\\\\1.1.1.1\\c$\\edata\\ecl\\regress\\process0.dll");
  727. const char * abcFilename = "\\\\127.0.0.1\\c$\\temp\\dlltest\abc";
  728. Owned<IFile> temp = createIFile(abcFilename);
  729. recursiveCreateDirectoryForFile(abcFilename);
  730. Owned<IFileIO> io = temp->open(IFOcreate);
  731. io->write(0, 10, "abcdefghij");
  732. io.clear();
  733. server.registerDll("WorkUnitAbc","workunit",abcFilename);
  734. server.removeDll("WorkUnitAbc", true, true);
  735. cleanUpOldDlls();
  736. }