MQTTPersistenceDefault.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /*******************************************************************************
  2. * Copyright (c) 2009, 2018 IBM Corp.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v1.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * http://www.eclipse.org/legal/epl-v10.html
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. * Contributors:
  14. * Ian Craggs - initial API and implementation and/or initial documentation
  15. * Ian Craggs - async client updates
  16. * Ian Craggs - fix for bug 484496
  17. * Ian Craggs - fix for issue 285
  18. *******************************************************************************/
  19. /**
  20. * @file
  21. * \brief A file system based persistence implementation.
  22. *
  23. * A directory is specified when the MQTT client is created. When the persistence is then
  24. * opened (see ::Persistence_open), a sub-directory is made beneath the base for this
  25. * particular client ID and connection key. This allows one persistence base directory to
  26. * be shared by multiple clients.
  27. *
  28. */
  29. #if !defined(NO_PERSISTENCE)
  30. #include "OsWrapper.h"
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <errno.h>
  34. #if defined(WIN32) || defined(WIN64)
  35. #include <direct.h>
  36. /* Windows doesn't have strtok_r, so remap it to strtok */
  37. #define strtok_r( A, B, C ) strtok( A, B )
  38. int keysWin32(char *, char ***, int *);
  39. int clearWin32(char *);
  40. int containskeyWin32(char *, char *);
  41. #else
  42. #include <sys/stat.h>
  43. #include <dirent.h>
  44. #include <unistd.h>
  45. int keysUnix(char *, char ***, int *);
  46. int clearUnix(char *);
  47. int containskeyUnix(char *, char *);
  48. #endif
  49. #include "MQTTClientPersistence.h"
  50. #include "MQTTPersistenceDefault.h"
  51. #include "StackTrace.h"
  52. #include "Heap.h"
  53. /** Create persistence directory for the client: context/clientID-serverURI.
  54. * See ::Persistence_open
  55. */
  56. int pstopen(void **handle, const char* clientID, const char* serverURI, void* context)
  57. {
  58. int rc = 0;
  59. char *dataDir = context;
  60. char *clientDir;
  61. char *pToken = NULL;
  62. char *save_ptr = NULL;
  63. char *pCrtDirName = NULL;
  64. char *pTokDirName = NULL;
  65. char *perserverURI = NULL, *ptraux;
  66. FUNC_ENTRY;
  67. /* Note that serverURI=address:port, but ":" not allowed in Windows directories */
  68. perserverURI = malloc(strlen(serverURI) + 1);
  69. strcpy(perserverURI, serverURI);
  70. while ((ptraux = strstr(perserverURI, ":")) != NULL)
  71. *ptraux = '-' ;
  72. /* consider '/' + '-' + '\0' */
  73. clientDir = malloc(strlen(dataDir) + strlen(clientID) + strlen(perserverURI) + 3);
  74. sprintf(clientDir, "%s/%s-%s", dataDir, clientID, perserverURI);
  75. /* create clientDir directory */
  76. /* pCrtDirName - holds the directory name we are currently trying to create. */
  77. /* This gets built up level by level untipwdl the full path name is created.*/
  78. /* pTokDirName - holds the directory name that gets used by strtok. */
  79. pCrtDirName = (char*)malloc( strlen(clientDir) + 1 );
  80. pTokDirName = (char*)malloc( strlen(clientDir) + 1 );
  81. strcpy( pTokDirName, clientDir );
  82. /* If first character is directory separator, make sure it's in the created directory name #285 */
  83. if (*pTokDirName == '/' || *pTokDirName == '\\')
  84. {
  85. *pCrtDirName = *pTokDirName;
  86. pToken = strtok_r( pTokDirName + 1, "\\/", &save_ptr );
  87. strcpy( pCrtDirName + 1, pToken );
  88. }
  89. else
  90. {
  91. pToken = strtok_r( pTokDirName, "\\/", &save_ptr );
  92. strcpy( pCrtDirName, pToken );
  93. }
  94. rc = pstmkdir( pCrtDirName );
  95. pToken = strtok_r( NULL, "\\/", &save_ptr );
  96. while ( (pToken != NULL) && (rc == 0) )
  97. {
  98. /* Append the next directory level and try to create it */
  99. strcat( pCrtDirName, "/" );
  100. strcat( pCrtDirName, pToken );
  101. rc = pstmkdir( pCrtDirName );
  102. pToken = strtok_r( NULL, "\\/", &save_ptr );
  103. }
  104. *handle = clientDir;
  105. free(pTokDirName);
  106. free(pCrtDirName);
  107. free(perserverURI);
  108. FUNC_EXIT_RC(rc);
  109. return rc;
  110. }
  111. /** Function to create a directory.
  112. * Returns 0 on success or if the directory already exists.
  113. */
  114. int pstmkdir( char *pPathname )
  115. {
  116. int rc = 0;
  117. FUNC_ENTRY;
  118. #if defined(WIN32) || defined(WIN64)
  119. if ( _mkdir( pPathname ) != 0 )
  120. {
  121. #else
  122. /* Create a directory with read, write and execute access for the owner and read access for the group */
  123. #if !defined(_WRS_KERNEL)
  124. if ( mkdir( pPathname, S_IRWXU | S_IRGRP ) != 0 )
  125. #else
  126. if ( mkdir( pPathname ) != 0 )
  127. #endif /* !defined(_WRS_KERNEL) */
  128. {
  129. #endif
  130. if ( errno != EEXIST )
  131. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  132. }
  133. FUNC_EXIT_RC(rc);
  134. return rc;
  135. }
  136. /** Write wire message to the client persistence directory.
  137. * See ::Persistence_put
  138. */
  139. int pstput(void* handle, char* key, int bufcount, char* buffers[], int buflens[])
  140. {
  141. int rc = 0;
  142. char *clientDir = handle;
  143. char *file;
  144. FILE *fp;
  145. size_t bytesWritten = 0,
  146. bytesTotal = 0;
  147. int i;
  148. FUNC_ENTRY;
  149. if (clientDir == NULL)
  150. {
  151. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  152. goto exit;
  153. }
  154. /* consider '/' + '\0' */
  155. file = malloc(strlen(clientDir) + strlen(key) + strlen(MESSAGE_FILENAME_EXTENSION) + 2 );
  156. sprintf(file, "%s/%s%s", clientDir, key, MESSAGE_FILENAME_EXTENSION);
  157. fp = fopen(file, "wb");
  158. if ( fp != NULL )
  159. {
  160. for(i=0; i<bufcount; i++)
  161. {
  162. bytesTotal += buflens[i];
  163. bytesWritten += fwrite(buffers[i], sizeof(char), buflens[i], fp );
  164. }
  165. fclose(fp);
  166. fp = NULL;
  167. } else
  168. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  169. if (bytesWritten != bytesTotal)
  170. {
  171. pstremove(handle, key);
  172. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  173. }
  174. free(file);
  175. exit:
  176. FUNC_EXIT_RC(rc);
  177. return rc;
  178. };
  179. /** Retrieve a wire message from the client persistence directory.
  180. * See ::Persistence_get
  181. */
  182. int pstget(void* handle, char* key, char** buffer, int* buflen)
  183. {
  184. int rc = 0;
  185. FILE *fp;
  186. char *clientDir = handle;
  187. char *file;
  188. char *buf;
  189. unsigned long fileLen = 0;
  190. unsigned long bytesRead = 0;
  191. FUNC_ENTRY;
  192. if (clientDir == NULL)
  193. {
  194. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  195. goto exit;
  196. }
  197. /* consider '/' + '\0' */
  198. file = malloc(strlen(clientDir) + strlen(key) + strlen(MESSAGE_FILENAME_EXTENSION) + 2);
  199. sprintf(file, "%s/%s%s", clientDir, key, MESSAGE_FILENAME_EXTENSION);
  200. fp = fopen(file, "rb");
  201. if ( fp != NULL )
  202. {
  203. fseek(fp, 0, SEEK_END);
  204. fileLen = ftell(fp);
  205. fseek(fp, 0, SEEK_SET);
  206. buf=(char *)malloc(fileLen);
  207. bytesRead = (int)fread(buf, sizeof(char), fileLen, fp);
  208. *buffer = buf;
  209. *buflen = bytesRead;
  210. if ( bytesRead != fileLen )
  211. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  212. fclose(fp);
  213. fp = NULL;
  214. } else
  215. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  216. free(file);
  217. /* the caller must free buf */
  218. exit:
  219. FUNC_EXIT_RC(rc);
  220. return rc;
  221. }
  222. /** Delete a persisted message from the client persistence directory.
  223. * See ::Persistence_remove
  224. */
  225. int pstremove(void* handle, char* key)
  226. {
  227. int rc = 0;
  228. char *clientDir = handle;
  229. char *file;
  230. FUNC_ENTRY;
  231. if (clientDir == NULL)
  232. {
  233. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  234. goto exit;
  235. }
  236. /* consider '/' + '\0' */
  237. file = malloc(strlen(clientDir) + strlen(key) + strlen(MESSAGE_FILENAME_EXTENSION) + 2);
  238. sprintf(file, "%s/%s%s", clientDir, key, MESSAGE_FILENAME_EXTENSION);
  239. #if defined(WIN32) || defined(WIN64)
  240. if ( _unlink(file) != 0 )
  241. {
  242. #else
  243. if ( unlink(file) != 0 )
  244. {
  245. #endif
  246. if ( errno != ENOENT )
  247. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  248. }
  249. free(file);
  250. exit:
  251. FUNC_EXIT_RC(rc);
  252. return rc;
  253. }
  254. /** Delete client persistence directory (if empty).
  255. * See ::Persistence_close
  256. */
  257. int pstclose(void* handle)
  258. {
  259. int rc = 0;
  260. char *clientDir = handle;
  261. FUNC_ENTRY;
  262. if (clientDir == NULL)
  263. {
  264. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  265. goto exit;
  266. }
  267. #if defined(WIN32) || defined(WIN64)
  268. if ( _rmdir(clientDir) != 0 )
  269. {
  270. #else
  271. if ( rmdir(clientDir) != 0 )
  272. {
  273. #endif
  274. if ( errno != ENOENT && errno != ENOTEMPTY )
  275. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  276. }
  277. free(clientDir);
  278. exit:
  279. FUNC_EXIT_RC(rc);
  280. return rc;
  281. }
  282. /** Returns whether if a wire message is persisted in the client persistence directory.
  283. * See ::Persistence_containskey
  284. */
  285. int pstcontainskey(void *handle, char *key)
  286. {
  287. int rc = 0;
  288. char *clientDir = handle;
  289. FUNC_ENTRY;
  290. if (clientDir == NULL)
  291. {
  292. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  293. goto exit;
  294. }
  295. #if defined(WIN32) || defined(WIN64)
  296. rc = containskeyWin32(clientDir, key);
  297. #else
  298. rc = containskeyUnix(clientDir, key);
  299. #endif
  300. exit:
  301. FUNC_EXIT_RC(rc);
  302. return rc;
  303. }
  304. #if defined(WIN32) || defined(WIN64)
  305. int containskeyWin32(char *dirname, char *key)
  306. {
  307. int notFound = MQTTCLIENT_PERSISTENCE_ERROR;
  308. int fFinished = 0;
  309. char *filekey, *ptraux;
  310. char dir[MAX_PATH+1];
  311. WIN32_FIND_DATAA FileData;
  312. HANDLE hDir;
  313. FUNC_ENTRY;
  314. sprintf(dir, "%s/*", dirname);
  315. hDir = FindFirstFileA(dir, &FileData);
  316. if (hDir != INVALID_HANDLE_VALUE)
  317. {
  318. while (!fFinished)
  319. {
  320. if (FileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
  321. {
  322. filekey = malloc(strlen(FileData.cFileName) + 1);
  323. strcpy(filekey, FileData.cFileName);
  324. ptraux = strstr(filekey, MESSAGE_FILENAME_EXTENSION);
  325. if ( ptraux != NULL )
  326. *ptraux = '\0' ;
  327. if(strcmp(filekey, key) == 0)
  328. {
  329. notFound = 0;
  330. fFinished = 1;
  331. }
  332. free(filekey);
  333. }
  334. if (!FindNextFileA(hDir, &FileData))
  335. {
  336. if (GetLastError() == ERROR_NO_MORE_FILES)
  337. fFinished = 1;
  338. }
  339. }
  340. FindClose(hDir);
  341. }
  342. FUNC_EXIT_RC(notFound);
  343. return notFound;
  344. }
  345. #else
  346. int containskeyUnix(char *dirname, char *key)
  347. {
  348. int notFound = MQTTCLIENT_PERSISTENCE_ERROR;
  349. char *filekey, *ptraux;
  350. DIR *dp;
  351. struct dirent *dir_entry;
  352. struct stat stat_info;
  353. FUNC_ENTRY;
  354. if((dp = opendir(dirname)) != NULL)
  355. {
  356. while((dir_entry = readdir(dp)) != NULL && notFound)
  357. {
  358. char* filename = malloc(strlen(dirname) + strlen(dir_entry->d_name) + 2);
  359. sprintf(filename, "%s/%s", dirname, dir_entry->d_name);
  360. lstat(filename, &stat_info);
  361. free(filename);
  362. if(S_ISREG(stat_info.st_mode))
  363. {
  364. filekey = malloc(strlen(dir_entry->d_name) + 1);
  365. strcpy(filekey, dir_entry->d_name);
  366. ptraux = strstr(filekey, MESSAGE_FILENAME_EXTENSION);
  367. if ( ptraux != NULL )
  368. *ptraux = '\0' ;
  369. if(strcmp(filekey, key) == 0)
  370. notFound = 0;
  371. free(filekey);
  372. }
  373. }
  374. closedir(dp);
  375. }
  376. FUNC_EXIT_RC(notFound);
  377. return notFound;
  378. }
  379. #endif
  380. /** Delete all the persisted message in the client persistence directory.
  381. * See ::Persistence_clear
  382. */
  383. int pstclear(void *handle)
  384. {
  385. int rc = 0;
  386. char *clientDir = handle;
  387. FUNC_ENTRY;
  388. if (clientDir == NULL)
  389. {
  390. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  391. goto exit;
  392. }
  393. #if defined(WIN32) || defined(WIN64)
  394. rc = clearWin32(clientDir);
  395. #else
  396. rc = clearUnix(clientDir);
  397. #endif
  398. exit:
  399. FUNC_EXIT_RC(rc);
  400. return rc;
  401. }
  402. #if defined(WIN32) || defined(WIN64)
  403. int clearWin32(char *dirname)
  404. {
  405. int rc = 0;
  406. int fFinished = 0;
  407. char *file;
  408. char dir[MAX_PATH+1];
  409. WIN32_FIND_DATAA FileData;
  410. HANDLE hDir;
  411. FUNC_ENTRY;
  412. sprintf(dir, "%s/*", dirname);
  413. hDir = FindFirstFileA(dir, &FileData);
  414. if (hDir != INVALID_HANDLE_VALUE)
  415. {
  416. while (!fFinished)
  417. {
  418. if (FileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
  419. {
  420. file = malloc(strlen(dirname) + strlen(FileData.cFileName) + 2);
  421. sprintf(file, "%s/%s", dirname, FileData.cFileName);
  422. rc = remove(file);
  423. free(file);
  424. if ( rc != 0 )
  425. {
  426. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  427. break;
  428. }
  429. }
  430. if (!FindNextFileA(hDir, &FileData))
  431. {
  432. if (GetLastError() == ERROR_NO_MORE_FILES)
  433. fFinished = 1;
  434. }
  435. }
  436. FindClose(hDir);
  437. } else
  438. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  439. FUNC_EXIT_RC(rc);
  440. return rc;
  441. }
  442. #else
  443. int clearUnix(char *dirname)
  444. {
  445. int rc = 0;
  446. DIR *dp;
  447. struct dirent *dir_entry;
  448. struct stat stat_info;
  449. FUNC_ENTRY;
  450. if((dp = opendir(dirname)) != NULL)
  451. {
  452. while((dir_entry = readdir(dp)) != NULL && rc == 0)
  453. {
  454. lstat(dir_entry->d_name, &stat_info);
  455. if(S_ISREG(stat_info.st_mode))
  456. {
  457. if (remove(dir_entry->d_name) != 0 && errno != ENOENT)
  458. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  459. }
  460. }
  461. closedir(dp);
  462. } else
  463. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  464. FUNC_EXIT_RC(rc);
  465. return rc;
  466. }
  467. #endif
  468. /** Returns the keys (file names w/o the extension) in the client persistence directory.
  469. * See ::Persistence_keys
  470. */
  471. int pstkeys(void *handle, char ***keys, int *nkeys)
  472. {
  473. int rc = 0;
  474. char *clientDir = handle;
  475. FUNC_ENTRY;
  476. if (clientDir == NULL)
  477. {
  478. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  479. goto exit;
  480. }
  481. #if defined(WIN32) || defined(WIN64)
  482. rc = keysWin32(clientDir, keys, nkeys);
  483. #else
  484. rc = keysUnix(clientDir, keys, nkeys);
  485. #endif
  486. exit:
  487. FUNC_EXIT_RC(rc);
  488. return rc;
  489. }
  490. #if defined(WIN32) || defined(WIN64)
  491. int keysWin32(char *dirname, char ***keys, int *nkeys)
  492. {
  493. int rc = 0;
  494. char **fkeys = NULL;
  495. int nfkeys = 0;
  496. char dir[MAX_PATH+1];
  497. WIN32_FIND_DATAA FileData;
  498. HANDLE hDir;
  499. int fFinished = 0;
  500. char *ptraux;
  501. int i;
  502. FUNC_ENTRY;
  503. sprintf(dir, "%s/*", dirname);
  504. /* get number of keys */
  505. hDir = FindFirstFileA(dir, &FileData);
  506. if (hDir != INVALID_HANDLE_VALUE)
  507. {
  508. while (!fFinished)
  509. {
  510. if (FileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
  511. nfkeys++;
  512. if (!FindNextFileA(hDir, &FileData))
  513. {
  514. if (GetLastError() == ERROR_NO_MORE_FILES)
  515. fFinished = 1;
  516. }
  517. }
  518. FindClose(hDir);
  519. } else
  520. {
  521. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  522. goto exit;
  523. }
  524. if (nfkeys != 0 )
  525. fkeys = (char **)malloc(nfkeys * sizeof(char *));
  526. /* copy the keys */
  527. hDir = FindFirstFileA(dir, &FileData);
  528. if (hDir != INVALID_HANDLE_VALUE)
  529. {
  530. fFinished = 0;
  531. i = 0;
  532. while (!fFinished)
  533. {
  534. if (FileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
  535. {
  536. fkeys[i] = malloc(strlen(FileData.cFileName) + 1);
  537. strcpy(fkeys[i], FileData.cFileName);
  538. ptraux = strstr(fkeys[i], MESSAGE_FILENAME_EXTENSION);
  539. if ( ptraux != NULL )
  540. *ptraux = '\0' ;
  541. i++;
  542. }
  543. if (!FindNextFileA(hDir, &FileData))
  544. {
  545. if (GetLastError() == ERROR_NO_MORE_FILES)
  546. fFinished = 1;
  547. }
  548. }
  549. FindClose(hDir);
  550. } else
  551. {
  552. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  553. goto exit;
  554. }
  555. *nkeys = nfkeys;
  556. *keys = fkeys;
  557. /* the caller must free keys */
  558. exit:
  559. FUNC_EXIT_RC(rc);
  560. return rc;
  561. }
  562. #else
  563. int keysUnix(char *dirname, char ***keys, int *nkeys)
  564. {
  565. int rc = 0;
  566. char **fkeys = NULL;
  567. int nfkeys = 0;
  568. char *ptraux;
  569. int i;
  570. DIR *dp;
  571. struct dirent *dir_entry;
  572. struct stat stat_info;
  573. FUNC_ENTRY;
  574. /* get number of keys */
  575. if((dp = opendir(dirname)) != NULL)
  576. {
  577. while((dir_entry = readdir(dp)) != NULL)
  578. {
  579. char* temp = malloc(strlen(dirname)+strlen(dir_entry->d_name)+2);
  580. sprintf(temp, "%s/%s", dirname, dir_entry->d_name);
  581. if (lstat(temp, &stat_info) == 0 && S_ISREG(stat_info.st_mode))
  582. nfkeys++;
  583. free(temp);
  584. }
  585. closedir(dp);
  586. } else
  587. {
  588. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  589. goto exit;
  590. }
  591. if (nfkeys != 0)
  592. {
  593. fkeys = (char **)malloc(nfkeys * sizeof(char *));
  594. /* copy the keys */
  595. if((dp = opendir(dirname)) != NULL)
  596. {
  597. i = 0;
  598. while((dir_entry = readdir(dp)) != NULL)
  599. {
  600. char* temp = malloc(strlen(dirname)+strlen(dir_entry->d_name)+2);
  601. sprintf(temp, "%s/%s", dirname, dir_entry->d_name);
  602. if (lstat(temp, &stat_info) == 0 && S_ISREG(stat_info.st_mode))
  603. {
  604. fkeys[i] = malloc(strlen(dir_entry->d_name) + 1);
  605. strcpy(fkeys[i], dir_entry->d_name);
  606. ptraux = strstr(fkeys[i], MESSAGE_FILENAME_EXTENSION);
  607. if ( ptraux != NULL )
  608. *ptraux = '\0' ;
  609. i++;
  610. }
  611. free(temp);
  612. }
  613. closedir(dp);
  614. } else
  615. {
  616. rc = MQTTCLIENT_PERSISTENCE_ERROR;
  617. goto exit;
  618. }
  619. }
  620. *nkeys = nfkeys;
  621. *keys = fkeys;
  622. /* the caller must free keys */
  623. exit:
  624. FUNC_EXIT_RC(rc);
  625. return rc;
  626. }
  627. #endif
  628. #if defined(UNIT_TESTS)
  629. int main (int argc, char *argv[])
  630. {
  631. #define MSTEM "m-"
  632. #define NMSGS 10
  633. #define NBUFS 4
  634. #define NDEL 2
  635. #define RC !rc ? "(Success)" : "(Failed) "
  636. int rc;
  637. char *handle;
  638. char *perdir = ".";
  639. const char *clientID = "TheUTClient";
  640. const char *serverURI = "127.0.0.1:1883";
  641. char *stem = MSTEM;
  642. int msgId, i;
  643. int nm[NDEL] = {5 , 8}; /* msgIds to get and remove */
  644. char *key;
  645. char **keys;
  646. int nkeys;
  647. char *buffer, *buff;
  648. int buflen;
  649. int nbufs = NBUFS;
  650. char *bufs[NBUFS] = {"m0", "mm1", "mmm2" , "mmmm3"}; /* message content */
  651. int buflens[NBUFS];
  652. for(i=0;i<nbufs;i++)
  653. buflens[i]=strlen(bufs[i]);
  654. /* open */
  655. /* printf("Persistence directory : %s\n", perdir); */
  656. rc = pstopen((void**)&handle, clientID, serverURI, perdir);
  657. printf("%s Persistence directory for client %s : %s\n", RC, clientID, handle);
  658. /* put */
  659. for(msgId=0;msgId<NMSGS;msgId++)
  660. {
  661. key = malloc(MESSAGE_FILENAME_LENGTH + 1);
  662. sprintf(key, "%s%d", stem, msgId);
  663. rc = pstput(handle, key, nbufs, bufs, buflens);
  664. printf("%s Adding message %s\n", RC, key);
  665. free(key);
  666. }
  667. /* keys ,ie, list keys added */
  668. rc = pstkeys(handle, &keys, &nkeys);
  669. printf("%s Found %d messages persisted in %s\n", RC, nkeys, handle);
  670. for(i=0;i<nkeys;i++)
  671. printf("%13s\n", keys[i]);
  672. if (keys !=NULL)
  673. free(keys);
  674. /* containskey */
  675. for(i=0;i<NDEL;i++)
  676. {
  677. key = malloc(MESSAGE_FILENAME_LENGTH + 1);
  678. sprintf(key, "%s%d", stem, nm[i]);
  679. rc = pstcontainskey(handle, key);
  680. printf("%s Message %s is persisted ?\n", RC, key);
  681. free(key);
  682. }
  683. /* get && remove*/
  684. for(i=0;i<NDEL;i++)
  685. {
  686. key = malloc(MESSAGE_FILENAME_LENGTH + 1);
  687. sprintf(key, "%s%d", stem, nm[i]);
  688. rc = pstget(handle, key, &buffer, &buflen);
  689. buff = malloc(buflen+1);
  690. memcpy(buff, buffer, buflen);
  691. buff[buflen] = '\0';
  692. printf("%s Retrieving message %s : %s\n", RC, key, buff);
  693. rc = pstremove(handle, key);
  694. printf("%s Removing message %s\n", RC, key);
  695. free(key);
  696. free(buff);
  697. free(buffer);
  698. }
  699. /* containskey */
  700. for(i=0;i<NDEL;i++)
  701. {
  702. key = malloc(MESSAGE_FILENAME_LENGTH + 1);
  703. sprintf(key, "%s%d", stem, nm[i]);
  704. rc = pstcontainskey(handle, key);
  705. printf("%s Message %s is persisted ?\n", RC, key);
  706. free(key);
  707. }
  708. /* keys ,ie, list keys added */
  709. rc = pstkeys(handle, &keys, &nkeys);
  710. printf("%s Found %d messages persisted in %s\n", RC, nkeys, handle);
  711. for(i=0;i<nkeys;i++)
  712. printf("%13s\n", keys[i]);
  713. if (keys != NULL)
  714. free(keys);
  715. /* close -> it will fail, since client persistence directory is not empty */
  716. rc = pstclose(&handle);
  717. printf("%s Closing client persistence directory for client %s\n", RC, clientID);
  718. /* clear */
  719. rc = pstclear(handle);
  720. printf("%s Deleting all persisted messages in %s\n", RC, handle);
  721. /* keys ,ie, list keys added */
  722. rc = pstkeys(handle, &keys, &nkeys);
  723. printf("%s Found %d messages persisted in %s\n", RC, nkeys, handle);
  724. for(i=0;i<nkeys;i++)
  725. printf("%13s\n", keys[i]);
  726. if ( keys != NULL )
  727. free(keys);
  728. /* close */
  729. rc = pstclose(&handle);
  730. printf("%s Closing client persistence directory for client %s\n", RC, clientID);
  731. }
  732. #endif
  733. #endif /* NO_PERSISTENCE */