sorcery.c 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2012 - 2013, Digium, Inc.
  5. *
  6. * Joshua Colp <jcolp@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Sorcery Data Access Layer API
  21. *
  22. * \author Joshua Colp <jcolp@digium.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include "asterisk/logger.h"
  30. #include "asterisk/sorcery.h"
  31. #include "asterisk/astobj2.h"
  32. #include "asterisk/format.h"
  33. #include "asterisk/format_cap.h"
  34. #include "asterisk/strings.h"
  35. #include "asterisk/config_options.h"
  36. #include "asterisk/netsock2.h"
  37. #include "asterisk/module.h"
  38. #include "asterisk/taskprocessor.h"
  39. #include "asterisk/threadpool.h"
  40. #include "asterisk/json.h"
  41. #include "asterisk/format_pref.h"
  42. /* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */
  43. #undef open
  44. #undef close
  45. /*! \brief Number of buckets for wizards (should be prime for performance reasons) */
  46. #define WIZARD_BUCKETS 7
  47. /*! \brief Number of buckets for types (should be prime for performance reasons) */
  48. #define TYPE_BUCKETS 53
  49. /*! \brief Number of buckets for instances (should be prime for performance reasons) */
  50. #define INSTANCE_BUCKETS 17
  51. /*! \brief Number of buckets for object fields (should be prime for performance reasons) */
  52. #define OBJECT_FIELD_BUCKETS 29
  53. /*! \brief Thread pool for observers */
  54. static struct ast_threadpool *threadpool;
  55. /*! \brief Structure for internal sorcery object information */
  56. struct ast_sorcery_object {
  57. /*! \brief Unique identifier of this object */
  58. char *id;
  59. /*! \brief Type of object */
  60. char type[MAX_OBJECT_TYPE];
  61. /*! \brief Optional object destructor */
  62. ao2_destructor_fn destructor;
  63. /*! \brief Extended object fields */
  64. struct ast_variable *extended;
  65. };
  66. /*! \brief Structure for registered object type */
  67. struct ast_sorcery_object_type {
  68. /*! \brief Unique name of the object type */
  69. char name[MAX_OBJECT_TYPE];
  70. /*! \brief Optional transformation callback */
  71. sorcery_transform_handler transform;
  72. /*! \brief Optional object set apply callback */
  73. sorcery_apply_handler apply;
  74. /*! \brief Optional object copy callback */
  75. sorcery_copy_handler copy;
  76. /*! \brief Optional object diff callback */
  77. sorcery_diff_handler diff;
  78. /*! \brief Wizard instances */
  79. struct ao2_container *wizards;
  80. /*! \brief Object fields */
  81. struct ao2_container *fields;
  82. /*! \brief Configuration framework general information */
  83. struct aco_info *info;
  84. /*! \brief Configuration framework file information */
  85. struct aco_file *file;
  86. /*! \brief Type details */
  87. struct aco_type type;
  88. /*! \brief Observers */
  89. struct ao2_container *observers;
  90. /*! \brief Serializer for observers */
  91. struct ast_taskprocessor *serializer;
  92. /*! \brief Specifies if object type is reloadable or not */
  93. unsigned int reloadable:1;
  94. };
  95. /*! \brief Structure for registered object type observer */
  96. struct ast_sorcery_object_type_observer {
  97. /*! \brief Pointer to the observer implementation */
  98. const struct ast_sorcery_observer *callbacks;
  99. };
  100. /*! \brief Structure used for observer invocations */
  101. struct sorcery_observer_invocation {
  102. /*! \brief Pointer to the object type */
  103. struct ast_sorcery_object_type *object_type;
  104. /*! \brief Pointer to the object */
  105. void *object;
  106. };
  107. /*! \brief Structure for registered object field */
  108. struct ast_sorcery_object_field {
  109. /*! \brief Name of the field */
  110. char name[MAX_OBJECT_FIELD];
  111. /*! \brief Callback function for translation of a single value */
  112. sorcery_field_handler handler;
  113. /*! \brief Callback function for translation of multiple values */
  114. sorcery_fields_handler multiple_handler;
  115. /*! \brief Position of the field */
  116. intptr_t args[];
  117. };
  118. /*! \brief Structure for a wizard instance which operates on objects */
  119. struct ast_sorcery_object_wizard {
  120. /*! \brief Wizard interface itself */
  121. struct ast_sorcery_wizard *wizard;
  122. /*! \brief Unique data for the wizard */
  123. void *data;
  124. /*! \brief Wizard is acting as an object cache */
  125. unsigned int caching:1;
  126. };
  127. /*! \brief Full structure for sorcery */
  128. struct ast_sorcery {
  129. /*! \brief Container for known object types */
  130. struct ao2_container *types;
  131. /*! \brief The name of the module owning this sorcery instance */
  132. char module_name[0];
  133. };
  134. /*! \brief Structure for passing load/reload details */
  135. struct sorcery_load_details {
  136. /*! \brief Sorcery structure in use */
  137. const struct ast_sorcery *sorcery;
  138. /*! \brief Type of object being loaded */
  139. const char *type;
  140. /*! \brief Whether this is a reload or not */
  141. unsigned int reload:1;
  142. };
  143. /*! \brief Registered sorcery wizards */
  144. static struct ao2_container *wizards;
  145. /*! \brief Registered sorcery instances */
  146. static struct ao2_container *instances;
  147. static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
  148. {
  149. int *field = (int *)(obj + args[0]);
  150. return (ast_asprintf(buf, "%d", *field) < 0) ? -1 : 0;
  151. }
  152. static int uint_handler_fn(const void *obj, const intptr_t *args, char **buf)
  153. {
  154. unsigned int *field = (unsigned int *)(obj + args[0]);
  155. return (ast_asprintf(buf, "%u", *field) < 0) ? -1 : 0;
  156. }
  157. static int double_handler_fn(const void *obj, const intptr_t *args, char **buf)
  158. {
  159. double *field = (double *)(obj + args[0]);
  160. return (ast_asprintf(buf, "%f", *field) < 0) ? -1 : 0;
  161. }
  162. static int stringfield_handler_fn(const void *obj, const intptr_t *args, char **buf)
  163. {
  164. ast_string_field *field = (const char **)(obj + args[0]);
  165. return !(*buf = ast_strdup(*field)) ? -1 : 0;
  166. }
  167. static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf)
  168. {
  169. unsigned int *field = (unsigned int *)(obj + args[0]);
  170. return !(*buf = ast_strdup(*field ? "true" : "false")) ? -1 : 0;
  171. }
  172. static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf)
  173. {
  174. struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + args[0]);
  175. return !(*buf = ast_strdup(ast_sockaddr_stringify(field))) ? -1 : 0;
  176. }
  177. static int chararray_handler_fn(const void *obj, const intptr_t *args, char **buf)
  178. {
  179. char *field = (char *)(obj + args[0]);
  180. return !(*buf = ast_strdup(field)) ? -1 : 0;
  181. }
  182. static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf)
  183. {
  184. char tmp_buf[256];
  185. struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + args[0]);
  186. ast_codec_pref_string(pref, tmp_buf, sizeof(tmp_buf));
  187. return !(*buf = ast_strdup(tmp_buf));
  188. }
  189. static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type type)
  190. {
  191. switch(type) {
  192. case OPT_BOOL_T: return bool_handler_fn;
  193. case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
  194. case OPT_CODEC_T: return codec_handler_fn;
  195. case OPT_DOUBLE_T: return double_handler_fn;
  196. case OPT_INT_T: return int_handler_fn;
  197. case OPT_SOCKADDR_T: return sockaddr_handler_fn;
  198. case OPT_STRINGFIELD_T: return stringfield_handler_fn;
  199. case OPT_UINT_T: return uint_handler_fn;
  200. default:
  201. case OPT_CUSTOM_T: return NULL;
  202. }
  203. return NULL;
  204. }
  205. /*! \brief Hashing function for sorcery wizards */
  206. static int sorcery_wizard_hash(const void *obj, const int flags)
  207. {
  208. const struct ast_sorcery_wizard *object;
  209. const char *key;
  210. switch (flags & OBJ_SEARCH_MASK) {
  211. case OBJ_SEARCH_KEY:
  212. key = obj;
  213. break;
  214. case OBJ_SEARCH_OBJECT:
  215. object = obj;
  216. key = object->name;
  217. break;
  218. default:
  219. ast_assert(0);
  220. return 0;
  221. }
  222. return ast_str_hash(key);
  223. }
  224. /*! \brief Comparator function for sorcery wizards */
  225. static int sorcery_wizard_cmp(void *obj, void *arg, int flags)
  226. {
  227. const struct ast_sorcery_wizard *object_left = obj;
  228. const struct ast_sorcery_wizard *object_right = arg;
  229. const char *right_key = arg;
  230. int cmp;
  231. switch (flags & OBJ_SEARCH_MASK) {
  232. case OBJ_SEARCH_OBJECT:
  233. right_key = object_right->name;
  234. /* Fall through */
  235. case OBJ_SEARCH_KEY:
  236. cmp = strcmp(object_left->name, right_key);
  237. break;
  238. case OBJ_SEARCH_PARTIAL_KEY:
  239. cmp = strncmp(object_left->name, right_key, strlen(right_key));
  240. break;
  241. default:
  242. cmp = 0;
  243. break;
  244. }
  245. if (cmp) {
  246. return 0;
  247. }
  248. return CMP_MATCH;
  249. }
  250. /*! \brief Hashing function for sorcery wizards */
  251. static int object_type_field_hash(const void *obj, const int flags)
  252. {
  253. const struct ast_sorcery_object_field *object_field;
  254. const char *key;
  255. switch (flags & OBJ_SEARCH_MASK) {
  256. case OBJ_SEARCH_KEY:
  257. key = obj;
  258. break;
  259. case OBJ_SEARCH_OBJECT:
  260. object_field = obj;
  261. key = object_field->name;
  262. break;
  263. default:
  264. ast_assert(0);
  265. return 0;
  266. }
  267. return ast_str_hash(key);
  268. }
  269. static int object_type_field_cmp(void *obj, void *arg, int flags)
  270. {
  271. const struct ast_sorcery_object_field *field_left = obj;
  272. const struct ast_sorcery_object_field *field_right = arg;
  273. const char *right_key = arg;
  274. int cmp;
  275. switch (flags & OBJ_SEARCH_MASK) {
  276. case OBJ_SEARCH_OBJECT:
  277. right_key = field_right->name;
  278. /* Fall through */
  279. case OBJ_SEARCH_KEY:
  280. cmp = strcmp(field_left->name, right_key);
  281. break;
  282. case OBJ_SEARCH_PARTIAL_KEY:
  283. cmp = strncmp(field_left->name, right_key, strlen(right_key));
  284. break;
  285. default:
  286. cmp = 0;
  287. break;
  288. }
  289. if (cmp) {
  290. return 0;
  291. }
  292. return CMP_MATCH;
  293. }
  294. /*! \brief Cleanup function */
  295. static void sorcery_exit(void)
  296. {
  297. ast_threadpool_shutdown(threadpool);
  298. threadpool = NULL;
  299. }
  300. /*! \brief Cleanup function for graceful shutdowns */
  301. static void sorcery_cleanup(void)
  302. {
  303. ao2_cleanup(wizards);
  304. wizards = NULL;
  305. ao2_cleanup(instances);
  306. instances = NULL;
  307. }
  308. /*! \brief Compare function for sorcery instances */
  309. static int sorcery_instance_cmp(void *obj, void *arg, int flags)
  310. {
  311. const struct ast_sorcery *object_left = obj;
  312. const struct ast_sorcery *object_right = arg;
  313. const char *right_key = arg;
  314. int cmp;
  315. switch (flags & OBJ_SEARCH_MASK) {
  316. case OBJ_SEARCH_OBJECT:
  317. right_key = object_right->module_name;
  318. /* Fall through */
  319. case OBJ_SEARCH_KEY:
  320. cmp = strcmp(object_left->module_name, right_key);
  321. break;
  322. case OBJ_SEARCH_PARTIAL_KEY:
  323. cmp = strncmp(object_left->module_name, right_key, strlen(right_key));
  324. break;
  325. default:
  326. cmp = 0;
  327. break;
  328. }
  329. if (cmp) {
  330. return 0;
  331. }
  332. return CMP_MATCH;
  333. }
  334. /*! \brief Hashing function for sorcery instances */
  335. static int sorcery_instance_hash(const void *obj, const int flags)
  336. {
  337. const struct ast_sorcery *object;
  338. const char *key;
  339. switch (flags & OBJ_SEARCH_MASK) {
  340. case OBJ_SEARCH_KEY:
  341. key = obj;
  342. break;
  343. case OBJ_SEARCH_OBJECT:
  344. object = obj;
  345. key = object->module_name;
  346. break;
  347. default:
  348. ast_assert(0);
  349. return 0;
  350. }
  351. return ast_str_hash(key);
  352. }
  353. int ast_sorcery_init(void)
  354. {
  355. struct ast_threadpool_options options = {
  356. .version = AST_THREADPOOL_OPTIONS_VERSION,
  357. .auto_increment = 1,
  358. .max_size = 0,
  359. .idle_timeout = 60,
  360. .initial_size = 0,
  361. };
  362. ast_assert(wizards == NULL);
  363. if (!(threadpool = ast_threadpool_create("Sorcery", NULL, &options))) {
  364. threadpool = NULL;
  365. return -1;
  366. }
  367. if (!(wizards = ao2_container_alloc(WIZARD_BUCKETS, sorcery_wizard_hash, sorcery_wizard_cmp))) {
  368. ast_threadpool_shutdown(threadpool);
  369. return -1;
  370. }
  371. instances = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, INSTANCE_BUCKETS,
  372. sorcery_instance_hash, sorcery_instance_cmp);
  373. if (!instances) {
  374. sorcery_cleanup();
  375. sorcery_exit();
  376. return -1;
  377. }
  378. ast_register_cleanup(sorcery_cleanup);
  379. ast_register_atexit(sorcery_exit);
  380. return 0;
  381. }
  382. int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
  383. {
  384. struct ast_sorcery_wizard *wizard;
  385. int res = -1;
  386. ast_assert(!ast_strlen_zero(interface->name));
  387. ao2_lock(wizards);
  388. if ((wizard = ao2_find(wizards, interface->name, OBJ_KEY | OBJ_NOLOCK))) {
  389. ast_log(LOG_WARNING, "Attempted to register sorcery wizard '%s' twice\n",
  390. interface->name);
  391. goto done;
  392. }
  393. if (!(wizard = ao2_alloc(sizeof(*wizard), NULL))) {
  394. goto done;
  395. }
  396. *wizard = *interface;
  397. wizard->module = module;
  398. ao2_link_flags(wizards, wizard, OBJ_NOLOCK);
  399. res = 0;
  400. ast_verb(2, "Sorcery registered wizard '%s'\n", interface->name);
  401. done:
  402. ao2_cleanup(wizard);
  403. ao2_unlock(wizards);
  404. return res;
  405. }
  406. int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
  407. {
  408. RAII_VAR(struct ast_sorcery_wizard *, wizard, ao2_find(wizards, interface->name, OBJ_KEY | OBJ_UNLINK), ao2_cleanup);
  409. if (wizard) {
  410. ast_verb(2, "Sorcery unregistered wizard '%s'\n", interface->name);
  411. return 0;
  412. } else {
  413. return -1;
  414. }
  415. }
  416. /*! \brief Destructor called when sorcery structure is destroyed */
  417. static void sorcery_destructor(void *obj)
  418. {
  419. struct ast_sorcery *sorcery = obj;
  420. ao2_cleanup(sorcery->types);
  421. }
  422. /*! \brief Hashing function for sorcery types */
  423. static int sorcery_type_hash(const void *obj, const int flags)
  424. {
  425. const struct ast_sorcery_object_type *object;
  426. const char *key;
  427. switch (flags & OBJ_SEARCH_MASK) {
  428. case OBJ_SEARCH_KEY:
  429. key = obj;
  430. break;
  431. case OBJ_SEARCH_OBJECT:
  432. object = obj;
  433. key = object->name;
  434. break;
  435. default:
  436. ast_assert(0);
  437. return 0;
  438. }
  439. return ast_str_hash(key);
  440. }
  441. /*! \brief Comparator function for sorcery types */
  442. static int sorcery_type_cmp(void *obj, void *arg, int flags)
  443. {
  444. const struct ast_sorcery_object_type *object_left = obj;
  445. const struct ast_sorcery_object_type *object_right = arg;
  446. const char *right_key = arg;
  447. int cmp;
  448. switch (flags & OBJ_SEARCH_MASK) {
  449. case OBJ_SEARCH_OBJECT:
  450. right_key = object_right->name;
  451. /* Fall through */
  452. case OBJ_SEARCH_KEY:
  453. cmp = strcmp(object_left->name, right_key);
  454. break;
  455. case OBJ_SEARCH_PARTIAL_KEY:
  456. cmp = strncmp(object_left->name, right_key, strlen(right_key));
  457. break;
  458. default:
  459. cmp = 0;
  460. break;
  461. }
  462. if (cmp) {
  463. return 0;
  464. }
  465. return CMP_MATCH;
  466. }
  467. struct ast_sorcery *__ast_sorcery_open(const char *module_name)
  468. {
  469. struct ast_sorcery *sorcery;
  470. ast_assert(module_name != NULL);
  471. ao2_wrlock(instances);
  472. if ((sorcery = ao2_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK))) {
  473. goto done;
  474. }
  475. if (!(sorcery = ao2_alloc(sizeof(*sorcery) + strlen(module_name) + 1, sorcery_destructor))) {
  476. goto done;
  477. }
  478. if (!(sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS, sorcery_type_hash, sorcery_type_cmp))) {
  479. ao2_ref(sorcery, -1);
  480. sorcery = NULL;
  481. goto done;
  482. }
  483. strcpy(sorcery->module_name, module_name); /* Safe */
  484. if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) {
  485. ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.\n", module_name);
  486. ao2_cleanup(sorcery);
  487. sorcery = NULL;
  488. goto done;
  489. }
  490. ao2_link_flags(instances, sorcery, OBJ_NOLOCK);
  491. done:
  492. ao2_unlock(instances);
  493. return sorcery;
  494. }
  495. /*! \brief Search function for sorcery instances */
  496. struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module_name)
  497. {
  498. return ao2_find(instances, module_name, OBJ_SEARCH_KEY);
  499. }
  500. /*! \brief Destructor function for object types */
  501. static void sorcery_object_type_destructor(void *obj)
  502. {
  503. struct ast_sorcery_object_type *object_type = obj;
  504. ao2_cleanup(object_type->wizards);
  505. ao2_cleanup(object_type->fields);
  506. ao2_cleanup(object_type->observers);
  507. if (object_type->info) {
  508. aco_info_destroy(object_type->info);
  509. ast_free(object_type->info);
  510. }
  511. ast_free(object_type->file);
  512. ast_taskprocessor_unreference(object_type->serializer);
  513. }
  514. /*! \brief Internal function which allocates an object type structure */
  515. static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *type, const char *module)
  516. {
  517. struct ast_sorcery_object_type *object_type;
  518. char uuid[AST_UUID_STR_LEN];
  519. if (!(object_type = ao2_alloc(sizeof(*object_type), sorcery_object_type_destructor))) {
  520. return NULL;
  521. }
  522. /* Order matters for object wizards */
  523. if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, sorcery_wizard_cmp))) {
  524. ao2_ref(object_type, -1);
  525. return NULL;
  526. }
  527. if (!(object_type->fields = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, OBJECT_FIELD_BUCKETS,
  528. object_type_field_hash, object_type_field_cmp))) {
  529. ao2_ref(object_type, -1);
  530. return NULL;
  531. }
  532. if (!(object_type->observers = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, 1, NULL, NULL))) {
  533. ao2_ref(object_type, -1);
  534. return NULL;
  535. }
  536. if (!(object_type->info = ast_calloc(1, sizeof(*object_type->info) + 2 * sizeof(object_type->info->files[0])))) {
  537. ao2_ref(object_type, -1);
  538. return NULL;
  539. }
  540. if (!(object_type->file = ast_calloc(1, sizeof(*object_type->file) + 2 * sizeof(object_type->file->types[0])))) {
  541. ao2_ref(object_type, -1);
  542. return NULL;
  543. }
  544. if (!ast_uuid_generate_str(uuid, sizeof(uuid))) {
  545. ao2_ref(object_type, -1);
  546. return NULL;
  547. }
  548. if (!(object_type->serializer = ast_threadpool_serializer(uuid, threadpool))) {
  549. ao2_ref(object_type, -1);
  550. return NULL;
  551. }
  552. object_type->info->files[0] = object_type->file;
  553. object_type->info->files[1] = NULL;
  554. object_type->info->module = module;
  555. ast_copy_string(object_type->name, type, sizeof(object_type->name));
  556. return object_type;
  557. }
  558. /*! \brief Object wizard destructor */
  559. static void sorcery_object_wizard_destructor(void *obj)
  560. {
  561. struct ast_sorcery_object_wizard *object_wizard = obj;
  562. if (object_wizard->data) {
  563. object_wizard->wizard->close(object_wizard->data);
  564. }
  565. if (object_wizard->wizard) {
  566. ast_module_unref(object_wizard->wizard->module);
  567. }
  568. ao2_cleanup(object_wizard->wizard);
  569. }
  570. /*! \brief Internal function which creates an object type and adds a wizard mapping */
  571. static enum ast_sorcery_apply_result sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
  572. const char *type, const char *module, const char *name, const char *data, unsigned int caching)
  573. {
  574. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  575. RAII_VAR(struct ast_sorcery_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
  576. RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
  577. int created = 0;
  578. if (!wizard || !object_wizard) {
  579. return AST_SORCERY_APPLY_FAIL;
  580. }
  581. if (!object_type) {
  582. if (!(object_type = sorcery_object_type_alloc(type, module))) {
  583. return AST_SORCERY_APPLY_FAIL;
  584. }
  585. created = 1;
  586. }
  587. if (!created) {
  588. struct ast_sorcery_wizard *found;
  589. found = ao2_find(object_type->wizards, wizard, OBJ_SEARCH_OBJECT);
  590. if (found) {
  591. ast_debug(1, "Wizard %s already applied to object type %s\n",
  592. wizard->name, object_type->name);
  593. ao2_cleanup(found);
  594. return AST_SORCERY_APPLY_DUPLICATE;
  595. }
  596. }
  597. if (wizard->open && !(object_wizard->data = wizard->open(data))) {
  598. return AST_SORCERY_APPLY_FAIL;
  599. }
  600. ast_module_ref(wizard->module);
  601. object_wizard->wizard = ao2_bump(wizard);
  602. object_wizard->caching = caching;
  603. ao2_link(object_type->wizards, object_wizard);
  604. if (created) {
  605. ao2_link(sorcery->types, object_type);
  606. }
  607. return AST_SORCERY_APPLY_SUCCESS;
  608. }
  609. enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
  610. {
  611. struct ast_flags flags = { 0 };
  612. struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags);
  613. struct ast_variable *mapping;
  614. int res = AST_SORCERY_APPLY_SUCCESS;
  615. if (!config) {
  616. return AST_SORCERY_APPLY_NO_CONFIGURATION;
  617. }
  618. if (config == CONFIG_STATUS_FILEINVALID) {
  619. return AST_SORCERY_APPLY_FAIL;
  620. }
  621. for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) {
  622. RAII_VAR(char *, mapping_name, ast_strdup(mapping->name), ast_free);
  623. RAII_VAR(char *, mapping_value, ast_strdup(mapping->value), ast_free);
  624. char *options = mapping_name;
  625. char *type = strsep(&options, "/");
  626. char *data = mapping_value;
  627. char *wizard = strsep(&data, ",");
  628. unsigned int caching = 0;
  629. /* If no object type or wizard exists just skip, nothing we can do */
  630. if (ast_strlen_zero(type) || ast_strlen_zero(wizard)) {
  631. continue;
  632. }
  633. /* If the wizard is configured as a cache treat it as such */
  634. if (!ast_strlen_zero(options) && strstr(options, "cache")) {
  635. caching = 1;
  636. }
  637. /* Any error immediately causes us to stop */
  638. if (sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
  639. res = AST_SORCERY_APPLY_FAIL;
  640. break;
  641. }
  642. }
  643. ast_config_destroy(config);
  644. return res;
  645. }
  646. enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data)
  647. {
  648. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  649. /* Defaults can not be added if any existing mapping exists */
  650. if (object_type) {
  651. return AST_SORCERY_APPLY_DEFAULT_UNNECESSARY;
  652. }
  653. return sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
  654. }
  655. static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
  656. {
  657. return ast_sorcery_object_set_extended(obj, var->name, var->value);
  658. }
  659. static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
  660. {
  661. const struct ast_sorcery_object_details *details = obj;
  662. if (details->object->extended) {
  663. *fields = ast_variables_dup(details->object->extended);
  664. } else {
  665. *fields = NULL;
  666. }
  667. return 0;
  668. }
  669. int __ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, unsigned int hidden, unsigned int reloadable, aco_type_item_alloc alloc, sorcery_transform_handler transform, sorcery_apply_handler apply)
  670. {
  671. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  672. if (!object_type || object_type->type.item_alloc) {
  673. return -1;
  674. }
  675. object_type->type.name = object_type->name;
  676. object_type->type.type = ACO_ITEM;
  677. object_type->type.category = ".?";
  678. object_type->type.item_alloc = alloc;
  679. object_type->type.hidden = hidden;
  680. object_type->reloadable = reloadable;
  681. object_type->transform = transform;
  682. object_type->apply = apply;
  683. object_type->file->types[0] = &object_type->type;
  684. object_type->file->types[1] = NULL;
  685. if (aco_info_init(object_type->info)) {
  686. return -1;
  687. }
  688. if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
  689. return -1;
  690. }
  691. return 0;
  692. }
  693. void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
  694. {
  695. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  696. if (!object_type) {
  697. return;
  698. }
  699. object_type->copy = copy;
  700. }
  701. void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff)
  702. {
  703. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  704. if (!object_type) {
  705. return;
  706. }
  707. object_type->diff = diff;
  708. }
  709. int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
  710. {
  711. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  712. RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
  713. if (!object_type || !object_type->type.item_alloc || !config_handler || !(object_field = ao2_alloc(sizeof(*object_field), NULL))) {
  714. return -1;
  715. }
  716. ast_copy_string(object_field->name, regex, sizeof(object_field->name));
  717. object_field->multiple_handler = sorcery_handler;
  718. ao2_link(object_type->fields, object_field);
  719. __aco_option_register(object_type->info, regex, ACO_REGEX, object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 1, 0);
  720. return 0;
  721. }
  722. int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type,
  723. aco_option_handler config_handler, sorcery_field_handler sorcery_handler, sorcery_fields_handler multiple_handler, unsigned int flags, unsigned int no_doc, unsigned int alias, size_t argc, ...)
  724. {
  725. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  726. RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
  727. int pos;
  728. va_list args;
  729. if (!strcmp(type, "id") || !object_type || !object_type->type.item_alloc) {
  730. return -1;
  731. }
  732. if (!sorcery_handler) {
  733. sorcery_handler = sorcery_field_default_handler(opt_type);
  734. }
  735. if (!(object_field = ao2_alloc(sizeof(*object_field) + argc * sizeof(object_field->args[0]), NULL))) {
  736. return -1;
  737. }
  738. ast_copy_string(object_field->name, name, sizeof(object_field->name));
  739. object_field->handler = sorcery_handler;
  740. object_field->multiple_handler = multiple_handler;
  741. va_start(args, argc);
  742. for (pos = 0; pos < argc; pos++) {
  743. object_field->args[pos] = va_arg(args, size_t);
  744. }
  745. va_end(args);
  746. if (!alias) {
  747. ao2_link(object_type->fields, object_field);
  748. }
  749. /* TODO: Improve this hack */
  750. if (!argc) {
  751. __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc);
  752. } else if (argc == 1) {
  753. __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
  754. object_field->args[0]);
  755. } else if (argc == 2) {
  756. __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
  757. object_field->args[0], object_field->args[1]);
  758. } else if (argc == 3) {
  759. __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
  760. object_field->args[0], object_field->args[1], object_field->args[2]);
  761. } else {
  762. ast_assert(0); /* The hack... she does us no good for this */
  763. }
  764. return 0;
  765. }
  766. /*! \brief Retrieves whether or not the type is reloadable */
  767. static int sorcery_reloadable(const struct ast_sorcery *sorcery, const char *type)
  768. {
  769. RAII_VAR(struct ast_sorcery_object_type *, object_type,
  770. ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  771. return object_type && object_type->reloadable;
  772. }
  773. static int sorcery_wizard_load(void *obj, void *arg, int flags)
  774. {
  775. struct ast_sorcery_object_wizard *wizard = obj;
  776. struct sorcery_load_details *details = arg;
  777. void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type);
  778. if (details->reload && !sorcery_reloadable(details->sorcery, details->type)) {
  779. ast_log(LOG_NOTICE, "Type '%s' is not reloadable, "
  780. "maintaining previous values\n", details->type);
  781. return 0;
  782. }
  783. load = !details->reload ? wizard->wizard->load : wizard->wizard->reload;
  784. if (load) {
  785. load(wizard->data, details->sorcery, details->type);
  786. }
  787. return 0;
  788. }
  789. /*! \brief Destructor for observer invocation */
  790. static void sorcery_observer_invocation_destroy(void *obj)
  791. {
  792. struct sorcery_observer_invocation *invocation = obj;
  793. ao2_cleanup(invocation->object_type);
  794. ao2_cleanup(invocation->object);
  795. }
  796. /*! \brief Allocator function for observer invocation */
  797. static struct sorcery_observer_invocation *sorcery_observer_invocation_alloc(struct ast_sorcery_object_type *object_type, void *object)
  798. {
  799. struct sorcery_observer_invocation *invocation = ao2_alloc(sizeof(*invocation), sorcery_observer_invocation_destroy);
  800. if (!invocation) {
  801. return NULL;
  802. }
  803. ao2_ref(object_type, +1);
  804. invocation->object_type = object_type;
  805. if (object) {
  806. ao2_ref(object, +1);
  807. invocation->object = object;
  808. }
  809. return invocation;
  810. }
  811. /*! \brief Internal callback function which notifies an individual observer that an object type has been loaded */
  812. static int sorcery_observer_notify_loaded(void *obj, void *arg, int flags)
  813. {
  814. const struct ast_sorcery_object_type_observer *observer = obj;
  815. if (observer->callbacks->loaded) {
  816. observer->callbacks->loaded(arg);
  817. }
  818. return 0;
  819. }
  820. /*! \brief Internal callback function which notifies observers that an object type has been loaded */
  821. static int sorcery_observers_notify_loaded(void *data)
  822. {
  823. struct sorcery_observer_invocation *invocation = data;
  824. ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_loaded, invocation->object_type->name);
  825. ao2_cleanup(invocation);
  826. return 0;
  827. }
  828. static int sorcery_object_load(void *obj, void *arg, int flags)
  829. {
  830. struct ast_sorcery_object_type *type = obj;
  831. struct sorcery_load_details *details = arg;
  832. details->type = type->name;
  833. ao2_callback(type->wizards, OBJ_NODATA, sorcery_wizard_load, details);
  834. if (ao2_container_count(type->observers)) {
  835. struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(type, NULL);
  836. if (invocation && ast_taskprocessor_push(type->serializer, sorcery_observers_notify_loaded, invocation)) {
  837. ao2_cleanup(invocation);
  838. }
  839. }
  840. return 0;
  841. }
  842. void ast_sorcery_load(const struct ast_sorcery *sorcery)
  843. {
  844. struct sorcery_load_details details = {
  845. .sorcery = sorcery,
  846. .reload = 0,
  847. };
  848. ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
  849. }
  850. void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
  851. {
  852. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  853. struct sorcery_load_details details = {
  854. .sorcery = sorcery,
  855. .reload = 0,
  856. };
  857. if (!object_type) {
  858. return;
  859. }
  860. sorcery_object_load(object_type, &details, 0);
  861. }
  862. void ast_sorcery_reload(const struct ast_sorcery *sorcery)
  863. {
  864. struct sorcery_load_details details = {
  865. .sorcery = sorcery,
  866. .reload = 1,
  867. };
  868. ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
  869. }
  870. void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
  871. {
  872. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  873. struct sorcery_load_details details = {
  874. .sorcery = sorcery,
  875. .reload = 1,
  876. };
  877. if (!object_type) {
  878. return;
  879. }
  880. sorcery_object_load(object_type, &details, 0);
  881. }
  882. void ast_sorcery_ref(struct ast_sorcery *sorcery)
  883. {
  884. ao2_ref(sorcery, +1);
  885. }
  886. static struct ast_variable *get_single_field_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
  887. {
  888. struct ast_variable *tmp = NULL;
  889. char *buf = NULL;
  890. if (!object_field->handler) {
  891. return NULL;
  892. }
  893. if (!(object_field->handler(object, object_field->args, &buf))) {
  894. tmp = ast_variable_new(object_field->name, S_OR(buf, ""), "");
  895. }
  896. ast_free(buf);
  897. return tmp;
  898. }
  899. static struct ast_variable *get_multiple_fields_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
  900. {
  901. struct ast_variable *tmp = NULL;
  902. if (!object_field->multiple_handler) {
  903. return NULL;
  904. }
  905. if (object_field->multiple_handler(object, &tmp)) {
  906. ast_variables_destroy(tmp);
  907. tmp = NULL;
  908. }
  909. return tmp;
  910. }
  911. struct ast_variable *ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery,
  912. const void *object, enum ast_sorcery_field_handler_flags flags)
  913. {
  914. const struct ast_sorcery_object_details *details = object;
  915. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
  916. struct ao2_iterator i;
  917. struct ast_sorcery_object_field *object_field;
  918. struct ast_variable *head = NULL;
  919. struct ast_variable *tail = NULL;
  920. if (!object_type) {
  921. return NULL;
  922. }
  923. i = ao2_iterator_init(object_type->fields, 0);
  924. for (; (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
  925. struct ast_variable *tmp;
  926. switch (flags) {
  927. case AST_HANDLER_PREFER_LIST:
  928. if ((tmp = get_multiple_fields_as_var_list(object, object_field)) ||
  929. (tmp = get_single_field_as_var_list(object, object_field))) {
  930. break;
  931. }
  932. continue;
  933. case AST_HANDLER_PREFER_STRING:
  934. if ((tmp = get_single_field_as_var_list(object, object_field)) ||
  935. (tmp = get_multiple_fields_as_var_list(object, object_field))) {
  936. break;
  937. }
  938. continue;
  939. case AST_HANDLER_ONLY_LIST:
  940. if ((tmp = get_multiple_fields_as_var_list(object, object_field))) {
  941. break;
  942. }
  943. continue;
  944. case AST_HANDLER_ONLY_STRING:
  945. if ((tmp = get_single_field_as_var_list(object, object_field))) {
  946. break;
  947. }
  948. continue;
  949. default:
  950. continue;
  951. }
  952. tail = ast_variable_list_append_hint(&head, tail, tmp);
  953. }
  954. ao2_iterator_destroy(&i);
  955. return head;
  956. }
  957. struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
  958. {
  959. const struct ast_sorcery_object_details *details = object;
  960. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
  961. struct ao2_iterator i;
  962. struct ast_sorcery_object_field *object_field;
  963. struct ast_json *json = ast_json_object_create();
  964. int res = 0;
  965. if (!object_type || !json) {
  966. return NULL;
  967. }
  968. i = ao2_iterator_init(object_type->fields, 0);
  969. for (; !res && (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
  970. if (object_field->multiple_handler) {
  971. struct ast_variable *tmp = NULL;
  972. struct ast_variable *field;
  973. if ((res = object_field->multiple_handler(object, &tmp))) {
  974. ast_variables_destroy(tmp);
  975. ao2_ref(object_field, -1);
  976. break;
  977. }
  978. for (field = tmp; field; field = field->next) {
  979. struct ast_json *value = ast_json_string_create(field->value);
  980. if (!value || ast_json_object_set(json, field->name, value)) {
  981. res = -1;
  982. break;
  983. }
  984. }
  985. ast_variables_destroy(tmp);
  986. } else if (object_field->handler) {
  987. char *buf = NULL;
  988. struct ast_json *value = NULL;
  989. if ((res = object_field->handler(object, object_field->args, &buf))
  990. || !(value = ast_json_string_create(buf))
  991. || ast_json_object_set(json, object_field->name, value)) {
  992. res = -1;
  993. }
  994. ast_free(buf);
  995. } else {
  996. continue;
  997. }
  998. }
  999. ao2_iterator_destroy(&i);
  1000. /* If any error occurs we destroy the JSON object so a partial objectset is not returned */
  1001. if (res) {
  1002. ast_json_unref(json);
  1003. json = NULL;
  1004. }
  1005. return json;
  1006. }
  1007. int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
  1008. {
  1009. const struct ast_sorcery_object_details *details = object;
  1010. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
  1011. RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
  1012. struct ast_variable *field;
  1013. int res = 0;
  1014. if (!object_type) {
  1015. return -1;
  1016. }
  1017. if (object_type->transform && (transformed = object_type->transform(objectset))) {
  1018. field = transformed;
  1019. } else {
  1020. field = objectset;
  1021. }
  1022. for (; field; field = field->next) {
  1023. if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
  1024. break;
  1025. }
  1026. }
  1027. if (!res && object_type->apply) {
  1028. res = object_type->apply(sorcery, object);
  1029. }
  1030. return res;
  1031. }
  1032. static const struct ast_variable *sorcery_find_field(const struct ast_variable *fields, const char *name)
  1033. {
  1034. const struct ast_variable *field;
  1035. /* Search the linked list of fields to find the correct one */
  1036. for (field = fields; field; field = field->next) {
  1037. if (!strcmp(field->name, name)) {
  1038. return field;
  1039. }
  1040. }
  1041. return NULL;
  1042. }
  1043. int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
  1044. {
  1045. const struct ast_variable *field;
  1046. int res = 0;
  1047. *changes = NULL;
  1048. /* Unless the ast_variable list changes when examined... it can't differ from itself */
  1049. if (original == modified) {
  1050. return 0;
  1051. }
  1052. for (field = modified; field; field = field->next) {
  1053. const struct ast_variable *old = sorcery_find_field(original, field->name);
  1054. if (!old || strcmp(old->value, field->value)) {
  1055. struct ast_variable *tmp;
  1056. if (!(tmp = ast_variable_new(field->name, field->value, ""))) {
  1057. res = -1;
  1058. break;
  1059. }
  1060. tmp->next = *changes;
  1061. *changes = tmp;
  1062. }
  1063. }
  1064. /* If an error occurred do not return a partial changeset */
  1065. if (res) {
  1066. ast_variables_destroy(*changes);
  1067. *changes = NULL;
  1068. }
  1069. return res;
  1070. }
  1071. static void sorcery_object_destructor(void *object)
  1072. {
  1073. struct ast_sorcery_object_details *details = object;
  1074. if (details->object->destructor) {
  1075. details->object->destructor(object);
  1076. }
  1077. ast_variables_destroy(details->object->extended);
  1078. ast_free(details->object->id);
  1079. }
  1080. void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
  1081. {
  1082. void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
  1083. struct ast_sorcery_object_details *details = object;
  1084. if (!object) {
  1085. return NULL;
  1086. }
  1087. details->object = object + size;
  1088. details->object->destructor = destructor;
  1089. return object;
  1090. }
  1091. void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
  1092. {
  1093. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  1094. struct ast_sorcery_object_details *details;
  1095. if (!object_type || !object_type->type.item_alloc ||
  1096. !(details = object_type->type.item_alloc(id))) {
  1097. return NULL;
  1098. }
  1099. if (ast_strlen_zero(id)) {
  1100. char uuid[AST_UUID_STR_LEN];
  1101. ast_uuid_generate_str(uuid, sizeof(uuid));
  1102. details->object->id = ast_strdup(uuid);
  1103. } else {
  1104. details->object->id = ast_strdup(id);
  1105. }
  1106. ast_copy_string(details->object->type, type, sizeof(details->object->type));
  1107. if (aco_set_defaults(&object_type->type, id, details)) {
  1108. ao2_ref(details, -1);
  1109. return NULL;
  1110. }
  1111. return details;
  1112. }
  1113. void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
  1114. {
  1115. const struct ast_sorcery_object_details *details = object;
  1116. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
  1117. struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
  1118. RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
  1119. int res = 0;
  1120. if (!copy) {
  1121. return NULL;
  1122. } else if (object_type->copy) {
  1123. res = object_type->copy(object, copy);
  1124. } else if ((objectset = ast_sorcery_objectset_create(sorcery, object))) {
  1125. res = ast_sorcery_objectset_apply(sorcery, copy, objectset);
  1126. } else {
  1127. /* No native copy available and could not create an objectset, this copy has failed */
  1128. res = -1;
  1129. }
  1130. if (res) {
  1131. ao2_cleanup(copy);
  1132. copy = NULL;
  1133. }
  1134. return copy;
  1135. }
  1136. int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
  1137. {
  1138. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, ast_sorcery_object_get_type(original), OBJ_KEY), ao2_cleanup);
  1139. *changes = NULL;
  1140. if (strcmp(ast_sorcery_object_get_type(original), ast_sorcery_object_get_type(modified))) {
  1141. return -1;
  1142. }
  1143. if (original == modified) {
  1144. return 0;
  1145. } else if (!object_type->diff) {
  1146. RAII_VAR(struct ast_variable *, objectset1, NULL, ast_variables_destroy);
  1147. RAII_VAR(struct ast_variable *, objectset2, NULL, ast_variables_destroy);
  1148. objectset1 = ast_sorcery_objectset_create(sorcery, original);
  1149. objectset2 = ast_sorcery_objectset_create(sorcery, modified);
  1150. return ast_sorcery_changeset_create(objectset1, objectset2, changes);
  1151. } else {
  1152. return object_type->diff(original, modified, changes);
  1153. }
  1154. }
  1155. /*! \brief Structure used when calling create, update, or delete */
  1156. struct sorcery_details {
  1157. /*! \brief Pointer to the sorcery instance */
  1158. const struct ast_sorcery *sorcery;
  1159. /*! \brief Pointer to the object itself */
  1160. void *obj;
  1161. };
  1162. /*! \brief Internal function used to create an object in caching wizards */
  1163. static int sorcery_cache_create(void *obj, void *arg, int flags)
  1164. {
  1165. const struct ast_sorcery_object_wizard *object_wizard = obj;
  1166. const struct sorcery_details *details = arg;
  1167. if (!object_wizard->caching || !object_wizard->wizard->create) {
  1168. return 0;
  1169. }
  1170. object_wizard->wizard->create(details->sorcery, object_wizard->data, details->obj);
  1171. return 0;
  1172. }
  1173. void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
  1174. {
  1175. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  1176. void *object = NULL;
  1177. struct ao2_iterator i;
  1178. struct ast_sorcery_object_wizard *wizard;
  1179. unsigned int cached = 0;
  1180. if (!object_type || ast_strlen_zero(id)) {
  1181. return NULL;
  1182. }
  1183. i = ao2_iterator_init(object_type->wizards, 0);
  1184. for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
  1185. if (wizard->wizard->retrieve_id &&
  1186. !(object = wizard->wizard->retrieve_id(sorcery, wizard->data, object_type->name, id))) {
  1187. continue;
  1188. }
  1189. cached = wizard->caching;
  1190. ao2_ref(wizard, -1);
  1191. break;
  1192. }
  1193. ao2_iterator_destroy(&i);
  1194. if (!cached && object) {
  1195. ao2_callback(object_type->wizards, 0, sorcery_cache_create, object);
  1196. }
  1197. return object;
  1198. }
  1199. void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
  1200. {
  1201. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  1202. void *object = NULL;
  1203. struct ao2_iterator i;
  1204. struct ast_sorcery_object_wizard *wizard;
  1205. unsigned int cached = 0;
  1206. if (!object_type) {
  1207. return NULL;
  1208. }
  1209. /* If returning multiple objects create a container to store them in */
  1210. if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
  1211. if (!(object = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
  1212. return NULL;
  1213. }
  1214. }
  1215. /* Inquire with the available wizards for retrieval */
  1216. i = ao2_iterator_init(object_type->wizards, 0);
  1217. for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
  1218. if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
  1219. if (wizard->wizard->retrieve_multiple) {
  1220. wizard->wizard->retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
  1221. }
  1222. } else if (fields && wizard->wizard->retrieve_fields) {
  1223. if (wizard->wizard->retrieve_fields) {
  1224. object = wizard->wizard->retrieve_fields(sorcery, wizard->data, object_type->name, fields);
  1225. }
  1226. }
  1227. if ((flags & AST_RETRIEVE_FLAG_MULTIPLE) || !object) {
  1228. continue;
  1229. }
  1230. cached = wizard->caching;
  1231. ao2_ref(wizard, -1);
  1232. break;
  1233. }
  1234. ao2_iterator_destroy(&i);
  1235. /* If we are returning a single object and it came from a non-cache source create it in any caches */
  1236. if (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) && !cached && object) {
  1237. ao2_callback(object_type->wizards, 0, sorcery_cache_create, object);
  1238. }
  1239. return object;
  1240. }
  1241. struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
  1242. {
  1243. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  1244. struct ao2_container *objects;
  1245. struct ao2_iterator i;
  1246. struct ast_sorcery_object_wizard *wizard;
  1247. if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
  1248. return NULL;
  1249. }
  1250. i = ao2_iterator_init(object_type->wizards, 0);
  1251. for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
  1252. if (!wizard->wizard->retrieve_regex) {
  1253. continue;
  1254. }
  1255. wizard->wizard->retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
  1256. }
  1257. ao2_iterator_destroy(&i);
  1258. return objects;
  1259. }
  1260. /*! \brief Internal function which returns if the wizard has created the object */
  1261. static int sorcery_wizard_create(void *obj, void *arg, int flags)
  1262. {
  1263. const struct ast_sorcery_object_wizard *object_wizard = obj;
  1264. const struct sorcery_details *details = arg;
  1265. return (!object_wizard->caching && !object_wizard->wizard->create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0;
  1266. }
  1267. /*! \brief Internal callback function which notifies an individual observer that an object has been created */
  1268. static int sorcery_observer_notify_create(void *obj, void *arg, int flags)
  1269. {
  1270. const struct ast_sorcery_object_type_observer *observer = obj;
  1271. if (observer->callbacks->created) {
  1272. observer->callbacks->created(arg);
  1273. }
  1274. return 0;
  1275. }
  1276. /*! \brief Internal callback function which notifies observers that an object has been created */
  1277. static int sorcery_observers_notify_create(void *data)
  1278. {
  1279. struct sorcery_observer_invocation *invocation = data;
  1280. ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_create, invocation->object);
  1281. ao2_cleanup(invocation);
  1282. return 0;
  1283. }
  1284. int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
  1285. {
  1286. const struct ast_sorcery_object_details *details = object;
  1287. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
  1288. RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
  1289. struct sorcery_details sdetails = {
  1290. .sorcery = sorcery,
  1291. .obj = object,
  1292. };
  1293. if (!object_type) {
  1294. return -1;
  1295. }
  1296. if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_create, &sdetails)) &&
  1297. ao2_container_count(object_type->observers)) {
  1298. struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
  1299. if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) {
  1300. ao2_cleanup(invocation);
  1301. }
  1302. }
  1303. return object_wizard ? 0 : -1;
  1304. }
  1305. /*! \brief Internal callback function which notifies an individual observer that an object has been updated */
  1306. static int sorcery_observer_notify_update(void *obj, void *arg, int flags)
  1307. {
  1308. const struct ast_sorcery_object_type_observer *observer = obj;
  1309. if (observer->callbacks->updated) {
  1310. observer->callbacks->updated(arg);
  1311. }
  1312. return 0;
  1313. }
  1314. /*! \brief Internal callback function which notifies observers that an object has been updated */
  1315. static int sorcery_observers_notify_update(void *data)
  1316. {
  1317. struct sorcery_observer_invocation *invocation = data;
  1318. ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_update, invocation->object);
  1319. ao2_cleanup(invocation);
  1320. return 0;
  1321. }
  1322. /*! \brief Internal function which returns if a wizard has updated the object */
  1323. static int sorcery_wizard_update(void *obj, void *arg, int flags)
  1324. {
  1325. const struct ast_sorcery_object_wizard *object_wizard = obj;
  1326. const struct sorcery_details *details = arg;
  1327. return (object_wizard->wizard->update && !object_wizard->wizard->update(details->sorcery, object_wizard->data, details->obj) &&
  1328. !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
  1329. }
  1330. int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
  1331. {
  1332. const struct ast_sorcery_object_details *details = object;
  1333. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
  1334. RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
  1335. struct sorcery_details sdetails = {
  1336. .sorcery = sorcery,
  1337. .obj = object,
  1338. };
  1339. if (!object_type) {
  1340. return -1;
  1341. }
  1342. if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_update, &sdetails)) &&
  1343. ao2_container_count(object_type->observers)) {
  1344. struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
  1345. if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) {
  1346. ao2_cleanup(invocation);
  1347. }
  1348. }
  1349. return object_wizard ? 0 : -1;
  1350. }
  1351. /*! \brief Internal callback function which notifies an individual observer that an object has been deleted */
  1352. static int sorcery_observer_notify_delete(void *obj, void *arg, int flags)
  1353. {
  1354. const struct ast_sorcery_object_type_observer *observer = obj;
  1355. if (observer->callbacks->deleted) {
  1356. observer->callbacks->deleted(arg);
  1357. }
  1358. return 0;
  1359. }
  1360. /*! \brief Internal callback function which notifies observers that an object has been deleted */
  1361. static int sorcery_observers_notify_delete(void *data)
  1362. {
  1363. struct sorcery_observer_invocation *invocation = data;
  1364. ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_delete, invocation->object);
  1365. ao2_cleanup(invocation);
  1366. return 0;
  1367. }
  1368. /*! \brief Internal function which returns if a wizard has deleted the object */
  1369. static int sorcery_wizard_delete(void *obj, void *arg, int flags)
  1370. {
  1371. const struct ast_sorcery_object_wizard *object_wizard = obj;
  1372. const struct sorcery_details *details = arg;
  1373. return (object_wizard->wizard->delete && !object_wizard->wizard->delete(details->sorcery, object_wizard->data, details->obj) &&
  1374. !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
  1375. }
  1376. int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
  1377. {
  1378. const struct ast_sorcery_object_details *details = object;
  1379. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
  1380. RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
  1381. struct sorcery_details sdetails = {
  1382. .sorcery = sorcery,
  1383. .obj = object,
  1384. };
  1385. if (!object_type) {
  1386. return -1;
  1387. }
  1388. if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_delete, &sdetails)) &&
  1389. ao2_container_count(object_type->observers)) {
  1390. struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
  1391. if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) {
  1392. ao2_cleanup(invocation);
  1393. }
  1394. }
  1395. return object_wizard ? 0 : -1;
  1396. }
  1397. void ast_sorcery_unref(struct ast_sorcery *sorcery)
  1398. {
  1399. if (sorcery) {
  1400. /* One ref for what we just released, the other for the instances container. */
  1401. ao2_wrlock(instances);
  1402. if (ao2_ref(sorcery, -1) == 2) {
  1403. ao2_unlink_flags(instances, sorcery, OBJ_NOLOCK);
  1404. }
  1405. ao2_unlock(instances);
  1406. }
  1407. }
  1408. const char *ast_sorcery_object_get_id(const void *object)
  1409. {
  1410. const struct ast_sorcery_object_details *details = object;
  1411. return details->object->id;
  1412. }
  1413. const char *ast_sorcery_object_get_type(const void *object)
  1414. {
  1415. const struct ast_sorcery_object_details *details = object;
  1416. return details->object->type;
  1417. }
  1418. const char *ast_sorcery_object_get_extended(const void *object, const char *name)
  1419. {
  1420. const struct ast_sorcery_object_details *details = object;
  1421. struct ast_variable *field;
  1422. for (field = details->object->extended; field; field = field->next) {
  1423. if (!strcmp(field->name + 1, name)) {
  1424. return field->value;
  1425. }
  1426. }
  1427. return NULL;
  1428. }
  1429. int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
  1430. {
  1431. RAII_VAR(struct ast_variable *, field, NULL, ast_variables_destroy);
  1432. struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
  1433. const struct ast_sorcery_object_details *details = object;
  1434. if (!extended) {
  1435. return -1;
  1436. }
  1437. for (field = details->object->extended; field; previous = field, field = field->next) {
  1438. if (!strcmp(field->name, name)) {
  1439. if (previous) {
  1440. previous->next = field->next;
  1441. } else {
  1442. details->object->extended = field->next;
  1443. }
  1444. field->next = NULL;
  1445. break;
  1446. }
  1447. }
  1448. extended->next = details->object->extended;
  1449. details->object->extended = extended;
  1450. return 0;
  1451. }
  1452. int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
  1453. {
  1454. RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
  1455. struct ast_sorcery_object_type_observer *observer;
  1456. int res;
  1457. if (!object_type || !callbacks) {
  1458. return -1;
  1459. }
  1460. if (!(observer = ao2_alloc(sizeof(*observer), NULL))) {
  1461. return -1;
  1462. }
  1463. observer->callbacks = callbacks;
  1464. res = 0;
  1465. if (!ao2_link(object_type->observers, observer)) {
  1466. res = -1;
  1467. }
  1468. ao2_ref(observer, -1);
  1469. return res;
  1470. }
  1471. /*! \brief Internal callback function for removing an observer */
  1472. static int sorcery_observer_remove(void *obj, void *arg, int flags)
  1473. {
  1474. const struct ast_sorcery_object_type_observer *observer = obj;
  1475. return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
  1476. }
  1477. void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
  1478. {
  1479. RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
  1480. struct ast_sorcery_observer *cbs = (struct ast_sorcery_observer *) callbacks;/* Remove const for traversal. */
  1481. if (!sorcery) {
  1482. return;
  1483. }
  1484. object_type = ao2_find(sorcery->types, type, OBJ_KEY);
  1485. if (!object_type) {
  1486. return;
  1487. }
  1488. ao2_callback(object_type->observers, OBJ_NODATA | OBJ_UNLINK,
  1489. sorcery_observer_remove, cbs);
  1490. }
  1491. int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
  1492. {
  1493. const char *right_key = arg;
  1494. int cmp;
  1495. switch (flags & OBJ_SEARCH_MASK) {
  1496. case OBJ_SEARCH_OBJECT:
  1497. right_key = ast_sorcery_object_get_id(arg);
  1498. /* Fall through */
  1499. case OBJ_SEARCH_KEY:
  1500. cmp = strcmp(ast_sorcery_object_get_id(obj), right_key);
  1501. break;
  1502. case OBJ_SEARCH_PARTIAL_KEY:
  1503. cmp = strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key));
  1504. break;
  1505. default:
  1506. cmp = 0;
  1507. break;
  1508. }
  1509. return cmp;
  1510. }
  1511. int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
  1512. {
  1513. const char *right_key = arg;
  1514. int cmp = 0;
  1515. switch (flags & OBJ_SEARCH_MASK) {
  1516. case OBJ_SEARCH_OBJECT:
  1517. right_key = ast_sorcery_object_get_id(arg);
  1518. /* Fall through */
  1519. case OBJ_SEARCH_KEY:
  1520. if (strcmp(ast_sorcery_object_get_id(obj), right_key) == 0) {
  1521. cmp = CMP_MATCH | CMP_STOP;
  1522. }
  1523. break;
  1524. case OBJ_SEARCH_PARTIAL_KEY:
  1525. if (strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key)) == 0) {
  1526. cmp = CMP_MATCH;
  1527. }
  1528. break;
  1529. default:
  1530. cmp = 0;
  1531. break;
  1532. }
  1533. return cmp;
  1534. }
  1535. int ast_sorcery_object_id_hash(const void *obj, int flags) {
  1536. if (flags & OBJ_SEARCH_OBJECT) {
  1537. return ast_str_hash(ast_sorcery_object_get_id(obj));
  1538. } else if (flags & OBJ_SEARCH_KEY) {
  1539. return ast_str_hash(obj);
  1540. }
  1541. return -1;
  1542. }
  1543. struct ast_sorcery_object_type *ast_sorcery_get_object_type(const struct ast_sorcery *sorcery,
  1544. const char *type)
  1545. {
  1546. return ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
  1547. }
  1548. int ast_sorcery_is_object_field_registered(const struct ast_sorcery_object_type *object_type,
  1549. const char *field_name)
  1550. {
  1551. struct ast_sorcery_object_field *object_field;
  1552. int res = 1;
  1553. ast_assert(object_type != NULL);
  1554. object_field = ao2_find(object_type->fields, field_name, OBJ_SEARCH_KEY);
  1555. if (!object_field) {
  1556. res = 0;
  1557. }
  1558. ao2_cleanup(object_field);
  1559. return res;
  1560. }