dlg_profile.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360
  1. /*
  2. * Copyright (C) 2008 Voice System SRL
  3. *
  4. * This file is part of Kamailio, a free SIP server.
  5. *
  6. * Kamailio is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version
  10. *
  11. * Kamailio is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. */
  21. /*!
  22. * \file
  23. * \brief Profile related functions for the dialog module
  24. * \ingroup dialog
  25. * Module: \ref dialog
  26. */
  27. #include "../../mem/shm_mem.h"
  28. #include "../../hashes.h"
  29. #include "../../trim.h"
  30. #include "../../dprint.h"
  31. #include "../../ut.h"
  32. #include "../../route.h"
  33. #include "../../modules/tm/tm_load.h"
  34. #include "../../lib/srutils/sruid.h"
  35. #include "dlg_hash.h"
  36. #include "dlg_var.h"
  37. #include "dlg_handlers.h"
  38. #include "dlg_profile.h"
  39. /*! size of dialog profile hash */
  40. #define PROFILE_HASH_SIZE 16
  41. /*! tm bindings */
  42. extern struct tm_binds d_tmb;
  43. /*! global dialog message id */
  44. static unsigned int current_dlg_msg_id = 0 ;
  45. static unsigned int current_dlg_msg_pid = 0 ;
  46. /*! pending dialog links */
  47. static dlg_profile_link_t *current_pending_linkers = NULL;
  48. /*! global dialog profile list */
  49. static dlg_profile_table_t *profiles = NULL;
  50. static dlg_profile_table_t* new_dlg_profile( str *name,
  51. unsigned int size, unsigned int has_value);
  52. extern int update_dlg_timeout(dlg_cell_t *, int);
  53. static sruid_t _dlg_profile_sruid;
  54. /*!
  55. * \brief Add profile definitions to the global list
  56. * \see new_dlg_profile
  57. * \param profiles profile name
  58. * \param has_value set to 0 for a profile without value, otherwise it has a value
  59. * \return 0 on success, -1 on failure
  60. */
  61. int add_profile_definitions( char* profiles, unsigned int has_value)
  62. {
  63. char *p;
  64. char *d;
  65. str name;
  66. unsigned int i;
  67. if (profiles==NULL || strlen(profiles)==0 )
  68. return 0;
  69. p = profiles;
  70. do {
  71. /* locate name of profile */
  72. name.s = p;
  73. d = strchr( p, ';');
  74. if (d) {
  75. name.len = d-p;
  76. d++;
  77. } else {
  78. name.len = strlen(p);
  79. }
  80. /* we have the name -> trim it for spaces */
  81. trim_spaces_lr( name );
  82. /* check len name */
  83. if (name.len==0)
  84. /* ignore */
  85. continue;
  86. /* check the name format */
  87. for(i=0;i<name.len;i++) {
  88. if ( !isalnum(name.s[i]) && name.s[i] != '_' ) {
  89. LM_ERR("bad profile name <%.*s>, char %c - use only "
  90. "alphanumerical characters or '_'\n", name.len,name.s,name.s[i]);
  91. return -1;
  92. }
  93. }
  94. /* name ok -> create the profile */
  95. LM_DBG("creating profile <%.*s>\n",name.len,name.s);
  96. if (new_dlg_profile( &name, PROFILE_HASH_SIZE, has_value)==NULL) {
  97. LM_ERR("failed to create new profile <%.*s>\n",name.len,name.s);
  98. return -1;
  99. }
  100. }while( (p=d)!=NULL );
  101. return 0;
  102. }
  103. /*!
  104. * \brief Search a dialog profile in the global list
  105. * \note Linear search, this won't have the best performance for huge profile lists
  106. * \param name searched dialog profile
  107. * \return pointer to the profile on success, NULL otherwise
  108. */
  109. struct dlg_profile_table* search_dlg_profile(str *name)
  110. {
  111. struct dlg_profile_table *profile;
  112. for( profile=profiles ; profile ; profile=profile->next ) {
  113. if (name->len==profile->name.len &&
  114. memcmp(name->s,profile->name.s,name->len)==0 )
  115. return profile;
  116. }
  117. return NULL;
  118. }
  119. /*!
  120. * \brief Creates a new dialog profile
  121. * \see add_profile_definitions
  122. * \param name profile name
  123. * \param size profile size
  124. * \param has_value set to 0 for a profile without value, otherwise it has a value
  125. * \return pointer to the created dialog on success, NULL otherwise
  126. */
  127. static struct dlg_profile_table* new_dlg_profile( str *name, unsigned int size,
  128. unsigned int has_value)
  129. {
  130. struct dlg_profile_table *profile;
  131. struct dlg_profile_table *ptmp;
  132. unsigned int len;
  133. unsigned int i;
  134. if ( name->s==NULL || name->len==0 || size==0 ) {
  135. LM_ERR("invalid parameters\n");
  136. return NULL;
  137. }
  138. for( len=0,i=0 ; i<8*sizeof(size) ; i++ ) {
  139. if ( size & (1<<i) ) len++;
  140. }
  141. if (len!=1) {
  142. LM_ERR(" size %u is not power of 2!\n", size);
  143. return NULL;
  144. }
  145. profile = search_dlg_profile(name);
  146. if (profile!=NULL) {
  147. LM_ERR("duplicate dialog profile registered <%.*s>\n",
  148. name->len, name->s);
  149. return NULL;
  150. }
  151. len = sizeof(struct dlg_profile_table) +
  152. size*sizeof(struct dlg_profile_entry) +
  153. name->len + 1;
  154. profile = (struct dlg_profile_table *)shm_malloc(len);
  155. if (profile==NULL) {
  156. LM_ERR("no more shm mem\n");
  157. return NULL;
  158. }
  159. memset( profile , 0 , len);
  160. profile->size = size;
  161. profile->has_value = (has_value==0)?0:1;
  162. /* init lock */
  163. if (lock_init( &profile->lock )==NULL) {
  164. LM_ERR("failed to init lock\n");
  165. shm_free(profile);
  166. return NULL;
  167. }
  168. /* set inner pointers */
  169. profile->entries = (struct dlg_profile_entry*)(profile + 1);
  170. profile->name.s = ((char*)profile->entries) +
  171. size*sizeof(struct dlg_profile_entry);
  172. /* copy the name of the profile */
  173. memcpy( profile->name.s, name->s, name->len );
  174. profile->name.len = name->len;
  175. profile->name.s[profile->name.len] = 0;
  176. /* link profile */
  177. for( ptmp=profiles ; ptmp && ptmp->next; ptmp=ptmp->next );
  178. if (ptmp==NULL) {
  179. profiles = profile;
  180. sruid_init(&_dlg_profile_sruid, '-', "dlgp", SRUID_INC);
  181. } else {
  182. ptmp->next = profile;
  183. }
  184. return profile;
  185. }
  186. /*!
  187. * \brief Destroy a dialog profile list
  188. * \param profile dialog profile
  189. */
  190. static void destroy_dlg_profile(struct dlg_profile_table *profile)
  191. {
  192. if (profile==NULL)
  193. return;
  194. lock_destroy( &profile->lock );
  195. shm_free( profile );
  196. return;
  197. }
  198. /*!
  199. * \brief Destroy the global dialog profile list
  200. */
  201. void destroy_dlg_profiles(void)
  202. {
  203. struct dlg_profile_table *profile;
  204. while(profiles) {
  205. profile = profiles;
  206. profiles = profiles->next;
  207. destroy_dlg_profile( profile );
  208. }
  209. return;
  210. }
  211. /*!
  212. * \brief Destroy dialog linkers
  213. * \param linker dialog linker
  214. */
  215. void destroy_linkers(struct dlg_profile_link *linker)
  216. {
  217. struct dlg_profile_entry *p_entry;
  218. struct dlg_profile_link *l;
  219. struct dlg_profile_hash *lh;
  220. while(linker) {
  221. l = linker;
  222. linker = linker->next;
  223. /* unlink from profile table */
  224. if (l->hash_linker.next) {
  225. p_entry = &l->profile->entries[l->hash_linker.hash];
  226. lock_get( &l->profile->lock );
  227. lh = &l->hash_linker;
  228. /* last element on the list? */
  229. if (lh==lh->next) {
  230. p_entry->first = NULL;
  231. } else {
  232. if (p_entry->first==lh)
  233. p_entry->first = lh->next;
  234. lh->next->prev = lh->prev;
  235. lh->prev->next = lh->next;
  236. }
  237. lh->next = lh->prev = NULL;
  238. p_entry->content --;
  239. lock_release( &l->profile->lock );
  240. }
  241. /* free memory */
  242. shm_free(l);
  243. }
  244. }
  245. /*!
  246. * \brief Calculate the hash profile from a dialog
  247. * \see core_hash
  248. * \param value hash source
  249. * \param dlg dialog cell
  250. * \param profile dialog profile table (for hash size)
  251. * \return value hash if the value has a value, hash over dialog otherwise
  252. */
  253. inline static unsigned int calc_hash_profile(str *value1, str *value2,
  254. dlg_profile_table_t *profile)
  255. {
  256. if (profile->has_value) {
  257. /* do hash over the value1 */
  258. return core_hash( value1, NULL, profile->size);
  259. } else {
  260. /* do hash over the value2 */
  261. if(value2)
  262. return core_hash( value2, NULL, profile->size);
  263. return 0;
  264. }
  265. }
  266. /*!
  267. * \brief Remove remote profile items that are expired
  268. * \param te expiration time
  269. */
  270. void remove_expired_remote_profiles(time_t te)
  271. {
  272. struct dlg_profile_table *profile;
  273. struct dlg_profile_entry *p_entry;
  274. struct dlg_profile_hash *lh;
  275. struct dlg_profile_hash *kh;
  276. int i;
  277. for( profile=profiles ; profile ; profile=profile->next ) {
  278. if(profile->flags&FLAG_PROFILE_REMOTE) {
  279. for(i=0; i<profile->size; i++) {
  280. /* space for optimization */
  281. lock_get(&profile->lock);
  282. p_entry = &profile->entries[i];
  283. lh = p_entry->first;
  284. while(lh) {
  285. kh = lh->next;
  286. if(lh->dlg==NULL && lh->expires>0 && lh->expires<te) {
  287. /* last element on the list? */
  288. if (lh==lh->next) {
  289. p_entry->first = NULL;
  290. } else {
  291. if (p_entry->first==lh)
  292. p_entry->first = lh->next;
  293. lh->next->prev = lh->prev;
  294. lh->prev->next = lh->next;
  295. }
  296. lh->next = lh->prev = NULL;
  297. if(lh->linker) shm_free(lh->linker);
  298. p_entry->content--;
  299. lock_release(&profile->lock);
  300. return;
  301. }
  302. lh = kh;
  303. }
  304. lock_release(&profile->lock);
  305. }
  306. }
  307. }
  308. }
  309. /*!
  310. * \brief Remove profile
  311. * \param profile pointer to profile
  312. * \param value profile value
  313. * \param puid profile unique id
  314. */
  315. int remove_profile(dlg_profile_table_t *profile, str *value, str *puid)
  316. {
  317. unsigned int hash;
  318. struct dlg_profile_entry *p_entry;
  319. struct dlg_profile_hash *lh;
  320. hash = calc_hash_profile(value, puid, profile);
  321. lock_get(&profile->lock );
  322. p_entry = &profile->entries[hash];
  323. lh = p_entry->first;
  324. if(lh) {
  325. do {
  326. if(lh->dlg==NULL && lh->puid_len==puid->len
  327. && lh->value.len==value->len
  328. && strncmp(lh->puid, puid->s, puid->len)==0
  329. && strncmp(lh->value.s, value->s, value->len)==0) {
  330. /* last element on the list? */
  331. if (lh==lh->next) {
  332. p_entry->first = NULL;
  333. } else {
  334. if (p_entry->first==lh)
  335. p_entry->first = lh->next;
  336. lh->next->prev = lh->prev;
  337. lh->prev->next = lh->next;
  338. }
  339. lh->next = lh->prev = NULL;
  340. if(lh->linker) shm_free(lh->linker);
  341. p_entry->content--;
  342. return 1;
  343. }
  344. lh = lh->next;
  345. } while(lh != p_entry->first);
  346. }
  347. lock_release(&profile->lock );
  348. return 0;
  349. }
  350. /*!
  351. * \brief Callback for cleanup of profile local vars
  352. * \param msg SIP message
  353. * \param flags unused
  354. * \param param unused
  355. * \return 1
  356. */
  357. int cb_profile_reset( struct sip_msg *msg, unsigned int flags, void *param )
  358. {
  359. current_dlg_msg_id = 0;
  360. current_dlg_msg_pid = 0;
  361. if (current_pending_linkers) {
  362. destroy_linkers(current_pending_linkers);
  363. current_pending_linkers = NULL;
  364. }
  365. /* need to return non-zero - 0 will break the exec of the request */
  366. return 1;
  367. }
  368. /*!
  369. * \brief Cleanup a profile
  370. * \param msg SIP message
  371. * \param flags unused
  372. * \param param unused
  373. * \return 1
  374. */
  375. int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param )
  376. {
  377. dlg_cell_t *dlg;
  378. current_dlg_msg_id = 0;
  379. current_dlg_msg_pid = 0;
  380. dlg = dlg_get_ctx_dialog();
  381. if (dlg!=NULL) {
  382. if(dlg->dflags & DLG_FLAG_TM) {
  383. dlg_unref(dlg, 1);
  384. } else {
  385. /* dialog didn't make it to tm */
  386. dlg_unref(dlg, 2);
  387. }
  388. }
  389. if (current_pending_linkers) {
  390. destroy_linkers(current_pending_linkers);
  391. current_pending_linkers = NULL;
  392. }
  393. /* need to return non-zero - 0 will break the exec of the request */
  394. return 1;
  395. }
  396. /*!
  397. * \brief Link a dialog profile
  398. * \param linker dialog linker
  399. * \param vkey key for profile hash table
  400. */
  401. static void link_profile(struct dlg_profile_link *linker, str *vkey)
  402. {
  403. unsigned int hash;
  404. struct dlg_profile_entry *p_entry;
  405. /* calculate the hash position */
  406. hash = calc_hash_profile(&linker->hash_linker.value, vkey, linker->profile);
  407. linker->hash_linker.hash = hash;
  408. /* insert into profile hash table */
  409. p_entry = &linker->profile->entries[hash];
  410. lock_get( &linker->profile->lock );
  411. if (p_entry->first) {
  412. linker->hash_linker.prev = p_entry->first->prev;
  413. linker->hash_linker.next = p_entry->first;
  414. p_entry->first->prev->next = &linker->hash_linker;
  415. p_entry->first->prev = &linker->hash_linker;
  416. } else {
  417. p_entry->first = linker->hash_linker.next
  418. = linker->hash_linker.prev = &linker->hash_linker;
  419. }
  420. p_entry->content ++;
  421. lock_release( &linker->profile->lock );
  422. }
  423. /*!
  424. * \brief Link a dialog profile
  425. * \param linker dialog linker
  426. * \param dlg dialog cell
  427. */
  428. static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *dlg)
  429. {
  430. struct dlg_entry *d_entry;
  431. /* add the linker to the dialog */
  432. /* FIXME zero h_id is not 100% for testing if the dialog is inserted
  433. * into the hash table -> we need circular lists -bogdan */
  434. if (dlg->h_id) {
  435. d_entry = &d_table->entries[dlg->h_entry];
  436. dlg_lock( d_table, d_entry);
  437. linker->next = dlg->profile_links;
  438. dlg->profile_links =linker;
  439. linker->hash_linker.dlg = dlg;
  440. dlg_unlock( d_table, d_entry);
  441. } else {
  442. linker->next = dlg->profile_links;
  443. dlg->profile_links =linker;
  444. linker->hash_linker.dlg = dlg;
  445. }
  446. link_profile(linker, &dlg->callid);
  447. }
  448. /*!
  449. * \brief Set the global variables to the current dialog
  450. * \param msg SIP message
  451. * \param dlg dialog cell
  452. */
  453. void set_current_dialog(sip_msg_t *msg, dlg_cell_t *dlg)
  454. {
  455. struct dlg_profile_link *linker;
  456. struct dlg_profile_link *tlinker;
  457. LM_DBG("setting current dialog [%u:%u]\n", dlg->h_entry, dlg->h_id);
  458. /* if linkers are not from current request, just discard them */
  459. if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
  460. current_dlg_msg_id = msg->id;
  461. current_dlg_msg_pid = msg->pid;
  462. destroy_linkers(current_pending_linkers);
  463. } else {
  464. /* add the linker, one by one, to the dialog */
  465. linker = current_pending_linkers;
  466. while (linker) {
  467. tlinker = linker;
  468. linker = linker->next;
  469. /* process tlinker */
  470. tlinker->next = NULL;
  471. link_dlg_profile( tlinker, dlg);
  472. }
  473. }
  474. current_pending_linkers = NULL;
  475. }
  476. /*!
  477. * \brief Set a dialog profile
  478. * \param msg SIP message
  479. * \param value value
  480. * \param profile dialog profile table
  481. * \return 0 on success, -1 on failure
  482. */
  483. int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *profile)
  484. {
  485. dlg_cell_t *dlg = NULL;
  486. dlg_profile_link_t *linker;
  487. /* get current dialog */
  488. dlg = dlg_get_msg_dialog(msg);
  489. if (dlg==NULL && !is_route_type(REQUEST_ROUTE)) {
  490. LM_CRIT("BUG - dialog not found in a non REQUEST route (%d)\n",
  491. REQUEST_ROUTE);
  492. return -1;
  493. }
  494. /* build new linker */
  495. linker = (struct dlg_profile_link*)shm_malloc(
  496. sizeof(struct dlg_profile_link) + (profile->has_value?value->len:0) );
  497. if (linker==NULL) {
  498. LM_ERR("no more shm memory\n");
  499. goto error;
  500. }
  501. memset(linker, 0, sizeof(struct dlg_profile_link));
  502. /* set backpointers to profile and linker (itself) */
  503. linker->profile = profile;
  504. linker->hash_linker.linker = linker;
  505. /* set the value */
  506. if (profile->has_value) {
  507. linker->hash_linker.value.s = (char*)(linker+1);
  508. memcpy( linker->hash_linker.value.s, value->s, value->len);
  509. linker->hash_linker.value.len = value->len;
  510. }
  511. sruid_next_safe(&_dlg_profile_sruid);
  512. strcpy(linker->hash_linker.puid, _dlg_profile_sruid.uid.s);
  513. linker->hash_linker.puid_len = _dlg_profile_sruid.uid.len;
  514. if (dlg!=NULL) {
  515. /* add linker directly to the dialog and profile */
  516. link_dlg_profile( linker, dlg);
  517. } else {
  518. /* if existing linkers are not from current request, just discard them */
  519. if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
  520. current_dlg_msg_id = msg->id;
  521. current_dlg_msg_pid = msg->pid;
  522. destroy_linkers(current_pending_linkers);
  523. current_pending_linkers = NULL;
  524. }
  525. /* no dialog yet -> set linker as pending */
  526. if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
  527. current_dlg_msg_id = msg->id;
  528. current_dlg_msg_pid = msg->pid;
  529. destroy_linkers(current_pending_linkers);
  530. }
  531. linker->next = current_pending_linkers;
  532. current_pending_linkers = linker;
  533. }
  534. dlg_release(dlg);
  535. return 0;
  536. error:
  537. dlg_release(dlg);
  538. return -1;
  539. }
  540. /*!
  541. * \brief Add dialog to a profile
  542. * \param dlg dialog
  543. * \param value value
  544. * \param profile dialog profile table
  545. * \return 0 on success, -1 on failure
  546. */
  547. int dlg_add_profile(dlg_cell_t *dlg, str *value, struct dlg_profile_table *profile,
  548. str *puid, time_t expires, int flags)
  549. {
  550. dlg_profile_link_t *linker;
  551. str vkey;
  552. /* build new linker */
  553. linker = (struct dlg_profile_link*)shm_malloc(
  554. sizeof(struct dlg_profile_link) + (profile->has_value?(value->len+1):0) );
  555. if (linker==NULL) {
  556. LM_ERR("no more shm memory\n");
  557. goto error;
  558. }
  559. memset(linker, 0, sizeof(struct dlg_profile_link));
  560. /* set backpointers to profile and linker (itself) */
  561. linker->profile = profile;
  562. linker->hash_linker.linker = linker;
  563. /* set the value */
  564. if (profile->has_value) {
  565. linker->hash_linker.value.s = (char*)(linker+1);
  566. memcpy( linker->hash_linker.value.s, value->s, value->len);
  567. linker->hash_linker.value.len = value->len;
  568. linker->hash_linker.value.s[value->len] = '\0';
  569. }
  570. if(puid && puid->s && puid->len>0 && puid->len<SRUID_SIZE) {
  571. strcpy(linker->hash_linker.puid, puid->s);
  572. linker->hash_linker.puid_len = puid->len;
  573. } else {
  574. sruid_next_safe(&_dlg_profile_sruid);
  575. strcpy(linker->hash_linker.puid, _dlg_profile_sruid.uid.s);
  576. linker->hash_linker.puid_len = _dlg_profile_sruid.uid.len;
  577. }
  578. linker->hash_linker.expires = expires;
  579. linker->hash_linker.flags = flags;
  580. /* add linker directly to the dialog and profile */
  581. if(dlg!=NULL) {
  582. link_dlg_profile(linker, dlg);
  583. } else {
  584. vkey.s = linker->hash_linker.puid;
  585. vkey.len = linker->hash_linker.puid_len;
  586. profile->flags |= FLAG_PROFILE_REMOTE;
  587. link_profile(linker, &vkey);
  588. }
  589. return 0;
  590. error:
  591. return -1;
  592. }
  593. /*!
  594. * \brief Unset a dialog profile
  595. * \param msg SIP message
  596. * \param value value
  597. * \param profile dialog profile table
  598. * \return 1 on success, -1 on failure
  599. */
  600. int unset_dlg_profile(sip_msg_t *msg, str *value,
  601. dlg_profile_table_t *profile)
  602. {
  603. dlg_cell_t *dlg;
  604. dlg_profile_link_t *linker;
  605. dlg_profile_link_t *linker_prev;
  606. dlg_entry_t *d_entry;
  607. if (is_route_type(REQUEST_ROUTE)) {
  608. LM_ERR("dialog delete profile cannot be used in request route\n");
  609. return -1;
  610. }
  611. /* get current dialog */
  612. dlg = dlg_get_msg_dialog(msg);
  613. if (dlg==NULL) {
  614. LM_WARN("dialog is NULL for delete profile\n");
  615. return -1;
  616. }
  617. /* check the dialog linkers */
  618. d_entry = &d_table->entries[dlg->h_entry];
  619. dlg_lock( d_table, d_entry);
  620. linker = dlg->profile_links;
  621. linker_prev = NULL;
  622. for( ; linker ; linker_prev=linker,linker=linker->next) {
  623. if (linker->profile==profile) {
  624. if (profile->has_value==0) {
  625. goto found;
  626. } else if (value && value->len==linker->hash_linker.value.len &&
  627. memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
  628. goto found;
  629. }
  630. /* allow further search - maybe the dialog is inserted twice in
  631. * the same profile, but with different values -bogdan
  632. */
  633. }
  634. }
  635. dlg_unlock( d_table, d_entry);
  636. dlg_release(dlg);
  637. return -1;
  638. found:
  639. /* table still locked */
  640. /* remove the linker element from dialog */
  641. if (linker_prev==NULL) {
  642. dlg->profile_links = linker->next;
  643. } else {
  644. linker_prev->next = linker->next;
  645. }
  646. linker->next = NULL;
  647. dlg_unlock( d_table, d_entry);
  648. /* remove linker from profile table and free it */
  649. destroy_linkers(linker);
  650. dlg_release(dlg);
  651. return 1;
  652. }
  653. /*!
  654. * \brief Check if a dialog belongs to a profile
  655. * \param msg SIP message
  656. * \param profile dialog profile table
  657. * \param value value
  658. * \return 1 on success, -1 on failure
  659. */
  660. int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
  661. str *value)
  662. {
  663. struct dlg_cell *dlg;
  664. struct dlg_profile_link *linker;
  665. struct dlg_entry *d_entry;
  666. int ret;
  667. /* get current dialog */
  668. dlg = dlg_get_msg_dialog(msg);
  669. if (dlg==NULL)
  670. return -1;
  671. ret = -1;
  672. /* check the dialog linkers */
  673. d_entry = &d_table->entries[dlg->h_entry];
  674. dlg_lock( d_table, d_entry);
  675. for( linker=dlg->profile_links ; linker ; linker=linker->next) {
  676. if (linker->profile==profile) {
  677. if (profile->has_value==0) {
  678. dlg_unlock( d_table, d_entry);
  679. ret = 1;
  680. goto done;
  681. } else if (value && value->len==linker->hash_linker.value.len &&
  682. memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
  683. dlg_unlock( d_table, d_entry);
  684. ret = 1;
  685. goto done;
  686. }
  687. /* allow further search - maybe the dialog is inserted twice in
  688. * the same profile, but with different values -bogdan
  689. */
  690. }
  691. }
  692. dlg_unlock( d_table, d_entry);
  693. done:
  694. dlg_release(dlg);
  695. return ret;
  696. }
  697. /*!
  698. * \brief Get the size of a profile
  699. * \param profile evaluated profile
  700. * \param value value
  701. * \return the profile size
  702. */
  703. unsigned int get_profile_size(struct dlg_profile_table *profile, str *value)
  704. {
  705. unsigned int n,i;
  706. struct dlg_profile_hash *ph;
  707. if (profile->has_value==0 || value==NULL) {
  708. /* iterate through the hash and count all records */
  709. lock_get( &profile->lock );
  710. for( i=0,n=0 ; i<profile->size ; i++ )
  711. n += profile->entries[i].content;
  712. lock_release( &profile->lock );
  713. return n;
  714. } else {
  715. /* iterate through the hash entry and count only matching */
  716. /* calculate the hash position */
  717. i = calc_hash_profile( value, NULL, profile);
  718. n = 0;
  719. lock_get( &profile->lock );
  720. ph = profile->entries[i].first;
  721. if(ph) {
  722. do {
  723. /* compare */
  724. if ( value->len==ph->value.len &&
  725. memcmp(value->s,ph->value.s,value->len)==0 ) {
  726. /* found */
  727. n++;
  728. }
  729. /* next */
  730. ph=ph->next;
  731. }while( ph!=profile->entries[i].first );
  732. }
  733. lock_release( &profile->lock );
  734. return n;
  735. }
  736. }
  737. /*
  738. * Determine if message is in a dialog currently being tracked
  739. */
  740. int is_known_dlg(struct sip_msg *msg) {
  741. dlg_cell_t *dlg;
  742. dlg = dlg_get_msg_dialog(msg);
  743. if(dlg == NULL)
  744. return -1;
  745. dlg_release(dlg);
  746. return 1;
  747. }
  748. /*
  749. * \brief Set the timeout of all the dialogs in a given profile, by value.
  750. * \param profile The evaluated profile name.
  751. * \param value The value constraint.
  752. * \param timeout The dialog timeout to apply.
  753. */
  754. int dlg_set_timeout_by_profile(struct dlg_profile_table *profile,
  755. str *value, int timeout)
  756. {
  757. unsigned int i = 0;
  758. dlg_cell_t *this_dlg = NULL;
  759. struct dlg_profile_hash *ph = NULL;
  760. /* Private structure necessary for manipulating dialog
  761. * timeouts outside of profile locks. Admittedly, an
  762. * ugly hack, but avoids some concurrency issues.
  763. */
  764. struct dlg_map_list {
  765. unsigned int h_id;
  766. unsigned int h_entry;
  767. struct dlg_map_list *next;
  768. } *map_head, *map_scan, *map_scan_next;
  769. map_head = NULL;
  770. /* If the profile has no value, iterate through every
  771. * node and set its timeout.
  772. */
  773. if(profile->has_value == 0 || value == NULL) {
  774. lock_get(&profile->lock);
  775. for(i = 0; i < profile->size; i ++) {
  776. ph = profile->entries[i].first;
  777. if(!ph) continue;
  778. do {
  779. struct dlg_map_list *d = malloc(sizeof(struct dlg_map_list));
  780. if(!d)
  781. return -1;
  782. memset(d, 0, sizeof(struct dlg_map_list));
  783. d->h_id = ph->dlg->h_id;
  784. d->h_entry = ph->dlg->h_entry;
  785. if(map_head == NULL)
  786. map_head = d;
  787. else {
  788. d->next = map_head;
  789. map_head = d;
  790. }
  791. ph = ph->next;
  792. } while(ph != profile->entries[i].first);
  793. }
  794. lock_release(&profile->lock);
  795. }
  796. else {
  797. i = calc_hash_profile(value, NULL, profile);
  798. lock_get(&profile->lock);
  799. ph = profile->entries[i].first;
  800. if(ph) {
  801. do {
  802. if(ph && value->len == ph->value.len &&
  803. memcmp(value->s, ph->value.s, value->len) == 0) {
  804. struct dlg_map_list *d = malloc(sizeof(struct dlg_map_list));
  805. if(!d)
  806. return -1;
  807. memset(d, 0, sizeof(struct dlg_map_list));
  808. d->h_id = ph->dlg->h_id;
  809. d->h_entry = ph->dlg->h_entry;
  810. if(map_head == NULL)
  811. map_head = d;
  812. else {
  813. d->next = map_head;
  814. map_head = d;
  815. }
  816. }
  817. ph = ph->next;
  818. } while(ph && ph != profile->entries[i].first);
  819. }
  820. lock_release(&profile->lock);
  821. }
  822. /* Walk the list and bulk-set the timeout */
  823. for(map_scan = map_head; map_scan != NULL; map_scan = map_scan_next) {
  824. map_scan_next = map_scan->next;
  825. this_dlg = dlg_lookup(map_scan->h_entry, map_scan->h_id);
  826. if(!this_dlg) {
  827. LM_CRIT("Unable to find dialog %d:%d\n", map_scan->h_entry, map_scan->h_id);
  828. } else if(this_dlg->state >= DLG_STATE_EARLY) {
  829. if(update_dlg_timeout(this_dlg, timeout) < 0) {
  830. LM_ERR("Unable to set timeout on %d:%d\n", map_scan->h_entry,
  831. map_scan->h_id);
  832. }
  833. dlg_release(this_dlg);
  834. }
  835. free(map_scan);
  836. }
  837. return 0;
  838. }
  839. /****************************** MI commands *********************************/
  840. /*!
  841. * \brief Output a profile via MI interface
  842. * \param cmd_tree MI command tree
  843. * \param param unused
  844. * \return MI root output on success, NULL on failure
  845. */
  846. struct mi_root * mi_get_profile(struct mi_root *cmd_tree, void *param)
  847. {
  848. struct mi_node* node;
  849. struct mi_root* rpl_tree= NULL;
  850. struct mi_node* rpl = NULL;
  851. struct mi_attr* attr;
  852. struct dlg_profile_table *profile;
  853. str *value;
  854. str *profile_name;
  855. unsigned int size;
  856. int len;
  857. char *p;
  858. node = cmd_tree->node.kids;
  859. if (node==NULL || !node->value.s || !node->value.len)
  860. return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
  861. profile_name = &node->value;
  862. if (node->next) {
  863. node = node->next;
  864. if (!node->value.s || !node->value.len)
  865. return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
  866. if (node->next)
  867. return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
  868. value = &node->value;
  869. } else {
  870. value = NULL;
  871. }
  872. /* search for the profile */
  873. profile = search_dlg_profile( profile_name );
  874. if (profile==NULL)
  875. return init_mi_tree( 404, MI_SSTR("Profile not found"));
  876. size = get_profile_size( profile , value );
  877. rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
  878. if (rpl_tree==0)
  879. return 0;
  880. rpl = &rpl_tree->node;
  881. node = add_mi_node_child(rpl, MI_DUP_VALUE, "profile", 7, NULL, 0);
  882. if (node==0) {
  883. free_mi_tree(rpl_tree);
  884. return NULL;
  885. }
  886. attr = add_mi_attr(node, MI_DUP_VALUE, "name", 4,
  887. profile->name.s, profile->name.len);
  888. if(attr == NULL) {
  889. goto error;
  890. }
  891. if (value) {
  892. attr = add_mi_attr(node, MI_DUP_VALUE, "value", 5, value->s, value->len);
  893. } else {
  894. attr = add_mi_attr(node, MI_DUP_VALUE, "value", 5, NULL, 0);
  895. }
  896. if(attr == NULL) {
  897. goto error;
  898. }
  899. p= int2str((unsigned long)size, &len);
  900. attr = add_mi_attr(node, MI_DUP_VALUE, "count", 5, p, len);
  901. if(attr == NULL) {
  902. goto error;
  903. }
  904. return rpl_tree;
  905. error:
  906. free_mi_tree(rpl_tree);
  907. return NULL;
  908. }
  909. /*!
  910. * \brief List the profiles via MI interface
  911. * \param cmd_tree MI command tree
  912. * \param param unused
  913. * \return MI root output on success, NULL on failure
  914. */
  915. struct mi_root * mi_profile_list(struct mi_root *cmd_tree, void *param )
  916. {
  917. struct mi_node* node;
  918. struct mi_root* rpl_tree= NULL;
  919. struct mi_node* rpl = NULL;
  920. struct dlg_profile_table *profile;
  921. struct dlg_profile_hash *ph;
  922. str *profile_name;
  923. str *value;
  924. unsigned int i;
  925. node = cmd_tree->node.kids;
  926. if (node==NULL || !node->value.s || !node->value.len)
  927. return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
  928. profile_name = &node->value;
  929. if (node->next) {
  930. node = node->next;
  931. if (!node->value.s || !node->value.len)
  932. return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
  933. if (node->next)
  934. return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
  935. value = &node->value;
  936. } else {
  937. value = NULL;
  938. }
  939. /* search for the profile */
  940. profile = search_dlg_profile( profile_name );
  941. if (profile==NULL)
  942. return init_mi_tree( 404, MI_SSTR("Profile not found"));
  943. rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
  944. if (rpl_tree==0)
  945. return 0;
  946. rpl = &rpl_tree->node;
  947. /* go through the hash and print the dialogs */
  948. if (profile->has_value==0 || value==NULL) {
  949. /* no value */
  950. lock_get( &profile->lock );
  951. for ( i=0 ; i< profile->size ; i++ ) {
  952. ph = profile->entries[i].first;
  953. if(ph) {
  954. do {
  955. /* print dialog */
  956. if ( mi_print_dlg( rpl, ph->dlg, 0)!=0 )
  957. goto error;
  958. /* next */
  959. ph=ph->next;
  960. }while( ph!=profile->entries[i].first );
  961. }
  962. }
  963. lock_release( &profile->lock );
  964. } else {
  965. /* check for value also */
  966. lock_get( &profile->lock );
  967. for ( i=0 ; i< profile->size ; i++ ) {
  968. ph = profile->entries[i].first;
  969. if(ph) {
  970. do {
  971. if ( value->len==ph->value.len &&
  972. memcmp(value->s,ph->value.s,value->len)==0 ) {
  973. /* print dialog */
  974. if ( mi_print_dlg( rpl, ph->dlg, 0)!=0 )
  975. goto error;
  976. }
  977. /* next */
  978. ph=ph->next;
  979. }while( ph!=profile->entries[i].first );
  980. }
  981. }
  982. lock_release( &profile->lock );
  983. }
  984. return rpl_tree;
  985. error:
  986. free_mi_tree(rpl_tree);
  987. return NULL;
  988. }
  989. /**
  990. * json serialization of dialog profiles
  991. */
  992. int dlg_profiles_to_json(dlg_cell_t *dlg, srjson_doc_t *jdoc)
  993. {
  994. dlg_profile_link_t *l;
  995. srjson_t *aj = NULL;
  996. srjson_t *pj = NULL;
  997. LM_DBG("serializing profiles for dlg[%u:%u]\n",
  998. dlg->h_entry, dlg->h_id);
  999. if(dlg==NULL || dlg->profile_links==NULL)
  1000. return -1;
  1001. LM_DBG("start of serializing profiles for dlg[%u:%u]\n",
  1002. dlg->h_entry, dlg->h_id);
  1003. for (l = dlg->profile_links ; l ; l=l->next) {
  1004. if(aj==NULL)
  1005. {
  1006. aj = srjson_CreateArray(jdoc);
  1007. if(aj==NULL)
  1008. {
  1009. LM_ERR("cannot create json profiles array object\n");
  1010. goto error;
  1011. }
  1012. }
  1013. pj = srjson_CreateObject(jdoc);
  1014. if(pj==NULL)
  1015. {
  1016. LM_ERR("cannot create json dynamic profiles obj\n");
  1017. goto error;
  1018. }
  1019. srjson_AddStrStrToObject(jdoc, pj,
  1020. "name", 4,
  1021. l->profile->name.s, l->profile->name.len);
  1022. if(l->profile->has_value)
  1023. {
  1024. srjson_AddStrStrToObject(jdoc, pj,
  1025. "value", 5,
  1026. l->hash_linker.value.s, l->hash_linker.value.len);
  1027. }
  1028. if(l->hash_linker.puid[0]!='\0')
  1029. srjson_AddStringToObject(jdoc, pj, "puid", l->hash_linker.puid);
  1030. if(l->hash_linker.expires!=0)
  1031. srjson_AddNumberToObject(jdoc, pj, "expires", l->hash_linker.expires);
  1032. if(l->hash_linker.flags!=0)
  1033. srjson_AddNumberToObject(jdoc, pj, "flags", l->hash_linker.flags);
  1034. srjson_AddItemToArray(jdoc, aj, pj);
  1035. }
  1036. if(jdoc->root==NULL)
  1037. {
  1038. jdoc->root = srjson_CreateObject(jdoc);
  1039. if(jdoc->root==NULL)
  1040. {
  1041. LM_ERR("cannot create json root\n");
  1042. goto error;
  1043. }
  1044. }
  1045. if(aj!=NULL)
  1046. srjson_AddItemToObject(jdoc, jdoc->root, "profiles", aj);
  1047. if(jdoc->buf.s != NULL)
  1048. {
  1049. jdoc->free_fn(jdoc->buf.s);
  1050. jdoc->buf.s = NULL;
  1051. jdoc->buf.len = 0;
  1052. }
  1053. jdoc->buf.s = srjson_PrintUnformatted(jdoc, jdoc->root);
  1054. if(jdoc->buf.s!=NULL)
  1055. {
  1056. jdoc->buf.len = strlen(jdoc->buf.s);
  1057. LM_DBG("serialized profiles for dlg[%u:%u] = [[%.*s]]\n",
  1058. dlg->h_entry, dlg->h_id, jdoc->buf.len, jdoc->buf.s);
  1059. return 0;
  1060. }
  1061. return -1;
  1062. error:
  1063. srjson_Delete(jdoc, aj);
  1064. return -1;
  1065. }
  1066. /**
  1067. * json de-serialization of dialog profiles
  1068. */
  1069. int dlg_json_to_profiles(dlg_cell_t *dlg, srjson_doc_t *jdoc)
  1070. {
  1071. srjson_t *aj = NULL;
  1072. srjson_t *it = NULL;
  1073. srjson_t *jt = NULL;
  1074. dlg_profile_table_t *profile;
  1075. str name;
  1076. str val;
  1077. str puid;
  1078. time_t expires;
  1079. int flags;
  1080. if(dlg==NULL || jdoc==NULL || jdoc->buf.s==NULL)
  1081. return -1;
  1082. if(jdoc->root == NULL)
  1083. {
  1084. jdoc->root = srjson_Parse(jdoc, jdoc->buf.s);
  1085. if(jdoc->root == NULL)
  1086. {
  1087. LM_ERR("invalid json doc [[%s]]\n", jdoc->buf.s);
  1088. return -1;
  1089. }
  1090. }
  1091. aj = srjson_GetObjectItem(jdoc, jdoc->root, "profiles");
  1092. if(aj!=NULL)
  1093. {
  1094. for(it=aj->child; it; it = it->next)
  1095. {
  1096. name.s = val.s = puid.s = NULL;
  1097. expires = 0; flags = 0;
  1098. for(jt = it->child; jt; jt = jt->next) {
  1099. if(strcmp(jt->string, "name")==0) {
  1100. name.s = jt->valuestring;
  1101. name.len = strlen(name.s);
  1102. } else if(strcmp(jt->string, "value")==0) {
  1103. val.s = jt->valuestring;
  1104. val.len = strlen(val.s);
  1105. } else if(strcmp(jt->string, "puid")==0) {
  1106. puid.s = jt->valuestring;
  1107. puid.len = strlen(puid.s);
  1108. } else if(strcmp(jt->string, "expires")==0) {
  1109. expires = (time_t)jt->valueint;
  1110. } else if(strcmp(jt->string, "flags")==0) {
  1111. flags = jt->valueint;
  1112. }
  1113. }
  1114. if(name.s==NULL)
  1115. continue;
  1116. profile = search_dlg_profile(&name);
  1117. if(profile==NULL)
  1118. {
  1119. LM_ERR("profile [%.*s] not found\n", name.len, name.s);
  1120. continue;
  1121. }
  1122. if(val.s!=NULL) {
  1123. if(profile->has_value)
  1124. {
  1125. if(dlg_add_profile(dlg, &val, profile, &puid, expires, flags) < 0)
  1126. LM_ERR("dynamic profile cannot be added, ignore!\n");
  1127. else
  1128. LM_DBG("dynamic profile added [%s : %s]\n", name.s, val.s);
  1129. }
  1130. } else {
  1131. if(!profile->has_value)
  1132. {
  1133. if(dlg_add_profile(dlg, NULL, profile, &puid, expires, flags) < 0)
  1134. LM_ERR("static profile cannot be added, ignore!\n");
  1135. else
  1136. LM_DBG("static profile added [%s]\n", name.s);
  1137. }
  1138. }
  1139. }
  1140. }
  1141. return 0;
  1142. }
  1143. /*!
  1144. *
  1145. */
  1146. int dlg_cmd_remote_profile(str *cmd, str *pname, str *value, str *puid,
  1147. time_t expires, int flags)
  1148. {
  1149. dlg_profile_table_t *dprofile;
  1150. int ret;
  1151. if(cmd==NULL || cmd->s==NULL || cmd->len<=0
  1152. || pname==NULL || pname->s==NULL || pname->len<=0
  1153. || puid==NULL || puid->s==NULL || puid->len<=0) {
  1154. LM_ERR("invalid parameters\n");
  1155. return -1;
  1156. }
  1157. dprofile = search_dlg_profile(pname);
  1158. if(dprofile==NULL) {
  1159. LM_ERR("profile [%.*s] not found\n", pname->len, pname->s);
  1160. return -1;
  1161. }
  1162. if(dprofile->has_value) {
  1163. if(value==NULL || value->s==NULL || value->len<=0) {
  1164. LM_ERR("profile [%.*s] requires a value\n", pname->len, pname->s);
  1165. return -1;
  1166. }
  1167. }
  1168. if(cmd->len==3 && strncmp(cmd->s, "add", 3)==0) {
  1169. if(value && value->s && value->len>0) {
  1170. ret = dlg_add_profile(NULL, value, dprofile, puid, expires, flags);
  1171. } else {
  1172. ret = dlg_add_profile(NULL, NULL, dprofile, puid, expires, flags);
  1173. }
  1174. if(ret<0) {
  1175. LM_ERR("failed to add to profile [%.*s]\n", pname->len, pname->s);
  1176. return -1;
  1177. }
  1178. } else if(cmd->len==2 && strncmp(cmd->s, "rm", 2)==0) {
  1179. ret = remove_profile(dprofile, value, puid);
  1180. return ret;
  1181. } else {
  1182. LM_ERR("unknown command [%.*s]\n", cmd->len, cmd->s);
  1183. return -1;
  1184. }
  1185. return 0;
  1186. }