cpl_run.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2001-2003 FhG Fokus
  5. *
  6. * This file is part of ser, a free SIP server.
  7. *
  8. * ser is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * For a license to use the ser software under conditions
  14. * other than those described here, or to purchase support for this
  15. * software, please contact iptel.org by e-mail at the following addresses:
  16. * [email protected]
  17. *
  18. * ser is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  26. *
  27. * History:
  28. * -------
  29. * 2003-01-23 : created (bogdan)
  30. * 2003-09-11 : build_lump_rpl() merged into add_lump_rpl() (bogdan)
  31. * 2004-06-14 : all global variables merged into cpl_env and cpl_fct;
  32. * append_branches param added to lookup node (bogdan)
  33. * 2004-06-14 : flag CPL_IS_STATEFUL is set now immediately after the
  34. * transaction is created (bogdan)
  35. */
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <time.h>
  39. #include <stdlib.h>
  40. #include "../../mem/mem.h"
  41. #include "../../mem/shm_mem.h"
  42. #include "../../str.h"
  43. #include "../../dprint.h"
  44. #include "../../parser/msg_parser.h"
  45. #include "../../data_lump_rpl.h"
  46. #include "../../modules/tm/tm_load.h"
  47. #include "../usrloc/usrloc.h"
  48. #include "CPL_tree.h"
  49. #include "loc_set.h"
  50. #include "cpl_utils.h"
  51. #include "cpl_nonsig.h"
  52. #include "cpl_sig.h"
  53. #include "cpl_env.h"
  54. #include "cpl_run.h"
  55. #define EO_SCRIPT ((char*)0xffffffff)
  56. #define DEFAULT_ACTION ((char*)0xfffffffe)
  57. #define CPL_SCRIPT_ERROR ((char*)0xfffffffd)
  58. #define CPL_RUNTIME_ERROR ((char*)0xfffffffc)
  59. #define CPL_TO_CONTINUE ((char*)0xfffffffb)
  60. #define HDR_NOT_FOUND ((char*)0xffffffff)
  61. #define UNDEF_CHAR (0xff)
  62. #define check_overflow_by_ptr(_ptr_,_intr_,_error_) \
  63. do {\
  64. if ( (char*)(_ptr_)>(_intr_)->script.len+(_intr_)->script.s ) {\
  65. LOG(L_ERR,"ERROR:cpl_c: overflow detected ip=%p ptr=%p in "\
  66. "func. %s, line %d\n",(_intr_)->ip,_ptr_,__FILE__,__LINE__);\
  67. goto _error_; \
  68. } \
  69. }while(0)
  70. #define check_overflow_by_offset(_len_,_intr_,_error_) \
  71. do {\
  72. if ( (char*)((_intr_)->ip+(_len_)) > \
  73. (_intr_)->script.len+(_intr_)->script.s ) {\
  74. LOG(L_ERR,"ERROR:cpl_c: overflow detected ip=%p offset=%d in "\
  75. "func. %s, line %d\n",(_intr_)->ip,_len_,__FILE__,__LINE__);\
  76. goto _error_; \
  77. } \
  78. }while(0)
  79. #define get_first_child(_node_) \
  80. ((NR_OF_KIDS(_node_)==0)?DEFAULT_ACTION:(_node_)+KID_OFFSET(_node_,0))
  81. #define get_basic_attr(_p_,_code_,_n_,_intr_,_error_) \
  82. do{\
  83. check_overflow_by_ptr( (_p_)+BASIC_ATTR_SIZE, _intr_, _error_);\
  84. _code_ = ntohs( *((unsigned short*)(_p_)) );\
  85. _n_ = ntohs( *((unsigned short*)((_p_)+2)) );\
  86. (_p_) += 4;\
  87. }while(0)
  88. #define get_str_attr(_p_,_s_,_len_,_intr_,_error_,_FIXUP_) \
  89. do{\
  90. if ( ((int)(_len_))-(_FIXUP_)<=0 ) {\
  91. LOG(L_ERR,"ERROR:cpl_c:%s:%d: attribute is an empty string\n",\
  92. __FILE__,__LINE__);\
  93. goto _error_; \
  94. } else {\
  95. check_overflow_by_ptr( (_p_)+(_len_), _intr_, _error_);\
  96. _s_ = _p_;\
  97. (_p_) += (_len_) + 1*(((_len_)&0x0001)==1);\
  98. (_len_) -= (_FIXUP_);\
  99. }\
  100. }while(0)
  101. struct cpl_interpreter* new_cpl_interpreter( struct sip_msg *msg, str *script)
  102. {
  103. struct cpl_interpreter *intr = 0;
  104. intr = (struct cpl_interpreter*)shm_malloc(sizeof(struct cpl_interpreter));
  105. if (!intr) {
  106. LOG(L_ERR,"ERROR:build_cpl_interpreter: no more free memory!\n");
  107. goto error;
  108. }
  109. memset( intr, 0, sizeof(struct cpl_interpreter));
  110. /* init the interpreter*/
  111. intr->script.s = script->s;
  112. intr->script.len = script->len;
  113. intr->recv_time = time(0);
  114. intr->ip = script->s;
  115. intr->msg = msg;
  116. /* check the beginning of the script */
  117. if ( NODE_TYPE(intr->ip)!=CPL_NODE ) {
  118. LOG(L_ERR,"ERROR:build_cpl_interpreter: first node is not CPL!!\n");
  119. goto error;
  120. }
  121. return intr;
  122. error:
  123. return 0;
  124. }
  125. void free_cpl_interpreter(struct cpl_interpreter *intr)
  126. {
  127. if (intr) {
  128. empty_location_set( &(intr->loc_set) );
  129. if (intr->script.s)
  130. shm_free( intr->script.s);
  131. if (intr->user.s)
  132. shm_free(intr->user.s);
  133. if (intr->flags&CPL_RURI_DUPLICATED)
  134. shm_free(intr->ruri);
  135. if (intr->flags&CPL_TO_DUPLICATED)
  136. shm_free(intr->to);
  137. if (intr->flags&CPL_FROM_DUPLICATED)
  138. shm_free(intr->from);
  139. if (intr->flags&CPL_SUBJECT_DUPLICATED)
  140. shm_free(intr->subject);
  141. if (intr->flags&CPL_ORGANIZATION_DUPLICATED)
  142. shm_free(intr->organization);
  143. if (intr->flags&CPL_USERAGENT_DUPLICATED)
  144. shm_free(intr->user_agent);
  145. if (intr->flags&CPL_ACCEPTLANG_DUPLICATED)
  146. shm_free(intr->accept_language);
  147. if (intr->flags&CPL_PRIORITY_DUPLICATED)
  148. shm_free(intr->priority);
  149. shm_free(intr);
  150. }
  151. }
  152. /* UPDATED + CHECKED
  153. */
  154. static inline char *run_cpl_node( struct cpl_interpreter *intr )
  155. {
  156. char *kid;
  157. unsigned char start;
  158. int i;
  159. start = (intr->flags&CPL_RUN_INCOMING)?INCOMING_NODE:OUTGOING_NODE;
  160. /* look for the starting node (incoming or outgoing) */
  161. for(i=0;i<NR_OF_KIDS(intr->ip);i++) {
  162. kid= intr->ip + KID_OFFSET(intr->ip,i);
  163. if ( NODE_TYPE(kid)==start ) {
  164. return get_first_child(kid);
  165. } else
  166. if (NODE_TYPE(kid)==SUBACTION_NODE ||
  167. NODE_TYPE(kid)==ANCILLARY_NODE ||
  168. NODE_TYPE(kid)==INCOMING_NODE ||
  169. NODE_TYPE(kid)==OUTGOING_NODE ) {
  170. continue;
  171. } else {
  172. LOG(L_ERR,"ERROR:cpl_c:run_cpl_node: unknown child type (%d) "
  173. "for CPL node!!\n",NODE_TYPE(kid));
  174. return CPL_SCRIPT_ERROR;
  175. }
  176. }
  177. DBG("DEBUG:cpl_c:run_cpl_node: CPL node has no %d subnode -> default\n",
  178. start);
  179. return DEFAULT_ACTION;
  180. }
  181. /* UPDATED + CHECKED
  182. */
  183. static inline char *run_lookup( struct cpl_interpreter *intr )
  184. {
  185. unsigned short attr_name;
  186. unsigned short n;
  187. unsigned char clear;
  188. char *p;
  189. char *kid;
  190. char *failure_kid = 0;
  191. char *success_kid = 0;
  192. char *notfound_kid = 0;
  193. int i;
  194. time_t tc;
  195. urecord_t* r;
  196. ucontact_t* contact;
  197. clear = NO_VAL;
  198. /* check the params */
  199. for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
  200. get_basic_attr(p,attr_name,n,intr,script_error);
  201. switch (attr_name) {
  202. case CLEAR_ATTR:
  203. if (n!=YES_VAL && n!=NO_VAL)
  204. LOG(L_WARN,"WARNING:run_lookup: invalid value (%u) found"
  205. " for param. CLEAR in LOOKUP node -> using "
  206. "default (%u)!\n",n,clear);
  207. else
  208. clear = n;
  209. break;
  210. default:
  211. LOG(L_ERR,"ERROR:run_lookup: unknown attribute (%d) in "
  212. "LOOKUP node\n",attr_name);
  213. goto script_error;
  214. }
  215. }
  216. /* check the kids */
  217. for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
  218. kid = intr->ip + KID_OFFSET(intr->ip,i);
  219. check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
  220. switch ( NODE_TYPE(kid) ) {
  221. case SUCCESS_NODE :
  222. success_kid = kid;
  223. break;
  224. case NOTFOUND_NODE:
  225. notfound_kid = kid;
  226. break;
  227. case FAILURE_NODE:
  228. failure_kid = kid;
  229. break;
  230. default:
  231. LOG(L_ERR,"ERROR:run_lookup: unknown output node type"
  232. " (%d) for LOOKUP node\n",NODE_TYPE(kid));
  233. goto script_error;
  234. }
  235. }
  236. kid = failure_kid;
  237. if (cpl_env.lu_domain) {
  238. /* fetch user's contacts via usrloc */
  239. tc = time(0);
  240. cpl_fct.ulb.lock_udomain( cpl_env.lu_domain );
  241. i = cpl_fct.ulb.get_urecord( cpl_env.lu_domain, &intr->user, &r);
  242. if (i < 0) {
  243. /* failure */
  244. LOG(L_ERR, "ERROR:run_lookup: Error while querying usrloc\n");
  245. cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain );
  246. } else if (i > 0) {
  247. /* not found */
  248. DBG("DBG:cpl-c:run_lookup: '%.*s' Not found in usrloc\n",
  249. intr->user.len, intr->user.s);
  250. cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain );
  251. kid = notfound_kid;
  252. } else {
  253. contact = r->contacts;
  254. /* skip expired contacts */
  255. while ( contact && contact->expires <= tc)
  256. contact = contact->next;
  257. /* any contacts left? */
  258. if (contact) {
  259. /* clear loc set if requested */
  260. if (clear)
  261. empty_location_set( &(intr->loc_set) );
  262. /* start adding locations to set */
  263. do {
  264. DBG("DBG:cpl-c:run_lookup: adding <%.*s>q=%d\n",
  265. contact->c.len,contact->c.s,(int)(10*contact->q));
  266. if (add_location( &(intr->loc_set), &contact->c,
  267. (int)(10*contact->q),
  268. CPL_LOC_DUPL|((contact->flags & FL_NAT)*CPL_LOC_NATED)
  269. )==-1) {
  270. LOG(L_ERR,"ERROR:cpl-c:run_lookup: unable to add "
  271. "location to set :-(\n");
  272. cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain );
  273. goto runtime_error;
  274. }
  275. contact = contact->next;
  276. }while( contact && cpl_env.lu_append_branches);
  277. /* set the flag for modifying the location set */
  278. intr->flags |= CPL_LOC_SET_MODIFIED;
  279. /* we found a valid contact */
  280. kid = success_kid;
  281. } else {
  282. /* no valid contact found */
  283. kid = notfound_kid;
  284. }
  285. cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain );
  286. }
  287. }
  288. if (kid)
  289. return get_first_child(kid);
  290. return DEFAULT_ACTION;
  291. runtime_error:
  292. return CPL_RUNTIME_ERROR;
  293. script_error:
  294. return CPL_SCRIPT_ERROR;
  295. }
  296. /* UPDATED + CHECKED
  297. */
  298. static inline char *run_location( struct cpl_interpreter *intr )
  299. {
  300. unsigned short attr_name;
  301. unsigned short n;
  302. char *p;
  303. unsigned char prio;
  304. unsigned char clear;
  305. str url;
  306. int i;
  307. clear = NO_VAL;
  308. prio = 10;
  309. url.s = (char*)UNDEF_CHAR;
  310. url.len = 0; /* fixes gcc 4.0 warning */
  311. /* sanity check */
  312. if (NR_OF_KIDS(intr->ip)>1) {
  313. LOG(L_ERR,"ERROR:run_location: LOCATION node suppose to have max "
  314. "one child, not %d!\n",NR_OF_KIDS(intr->ip));
  315. goto script_error;
  316. }
  317. for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
  318. get_basic_attr(p,attr_name,n,intr,script_error);
  319. switch (attr_name) {
  320. case URL_ATTR:
  321. url.len = n;
  322. get_str_attr( p, url.s, url.len, intr, script_error,1);
  323. break;
  324. case PRIORITY_ATTR:
  325. if ( n>10)
  326. LOG(L_WARN,"WARNING:run_location: invalid value (%u) found"
  327. " for param. PRIORITY in LOCATION node -> using "
  328. "default (%u)!\n",n,prio);
  329. else
  330. prio = n;
  331. break;
  332. case CLEAR_ATTR:
  333. if (n!=YES_VAL && n!=NO_VAL)
  334. LOG(L_WARN,"WARNING:run_location: invalid value (%u) found"
  335. " for param. CLEAR in LOCATION node -> using "
  336. "default (%u)!\n",n,clear);
  337. else
  338. clear = n;
  339. break;
  340. default:
  341. LOG(L_ERR,"ERROR:run_location: unknown attribute (%d) in "
  342. "LOCATION node\n",attr_name);
  343. goto script_error;
  344. }
  345. }
  346. if (url.s==(char*)UNDEF_CHAR) {
  347. LOG(L_ERR,"ERROR:run_location: param. URL missing in LOCATION node\n");
  348. goto script_error;
  349. }
  350. if (clear)
  351. empty_location_set( &(intr->loc_set) );
  352. if (add_location( &(intr->loc_set), &url, prio, 0/*no dup*/ )==-1) {
  353. LOG(L_ERR,"ERROR:run_location: unable to add location to set :-(\n");
  354. goto runtime_error;
  355. }
  356. /* set the flag for modifying the location set */
  357. intr->flags |= CPL_LOC_SET_MODIFIED;
  358. return get_first_child(intr->ip);
  359. runtime_error:
  360. return CPL_RUNTIME_ERROR;
  361. script_error:
  362. return CPL_SCRIPT_ERROR;
  363. }
  364. /* UPDATED + CHECKED
  365. */
  366. static inline char *run_remove_location( struct cpl_interpreter *intr )
  367. {
  368. unsigned short attr_name;
  369. unsigned short n;
  370. char *p;
  371. str url;
  372. int i;
  373. url.s = (char*)UNDEF_CHAR;
  374. /* sanity check */
  375. if (NR_OF_KIDS(intr->ip)>1) {
  376. LOG(L_ERR,"ERROR:cpl_c:run_remove_location: REMOVE_LOCATION node "
  377. "suppose to have max one child, not %d!\n",
  378. NR_OF_KIDS(intr->ip));
  379. goto script_error;
  380. }
  381. /* dirty hack to speed things up in when loc set is already empty */
  382. if (intr->loc_set==0)
  383. goto done;
  384. for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
  385. get_basic_attr(p,attr_name,n,intr,script_error);
  386. switch (attr_name) {
  387. case LOCATION_ATTR:
  388. url.len = n;
  389. get_str_attr( p, url.s, url.len, intr, script_error,1);
  390. break;
  391. default:
  392. LOG(L_ERR,"ERROR:run_remove_location: unknown attribute "
  393. "(%d) in REMOVE_LOCATION node\n",attr_name);
  394. goto script_error;
  395. }
  396. }
  397. if (url.s==(char*)UNDEF_CHAR) {
  398. DBG("DEBUG:run_remove_location: remove all locs from loc_set\n");
  399. empty_location_set( &(intr->loc_set) );
  400. } else {
  401. remove_location( &(intr->loc_set), url.s, url.len );
  402. }
  403. /* set the flag for modifying the location set */
  404. intr->flags |= CPL_LOC_SET_MODIFIED;
  405. done:
  406. return get_first_child(intr->ip);
  407. script_error:
  408. return CPL_SCRIPT_ERROR;
  409. }
  410. /* UPDATED + CHECKED
  411. */
  412. static inline char *run_sub( struct cpl_interpreter *intr )
  413. {
  414. char *p;
  415. unsigned short offset;
  416. unsigned short attr_name;
  417. int i;
  418. /* sanity check */
  419. if (NR_OF_KIDS(intr->ip)!=0) {
  420. LOG(L_ERR,"ERROR:cpl_c:run_sub: SUB node doesn't suppose to have any "
  421. "sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
  422. goto script_error;
  423. }
  424. /* check the number of attr */
  425. i = NR_OF_ATTR( intr->ip );
  426. if (i!=1) {
  427. LOG(L_ERR,"ERROR:cpl_c:run_sub: incorrect nr. of attr. %d (<>1) in "
  428. "SUB node\n",i);
  429. goto script_error;
  430. }
  431. /* get attr's name */
  432. p = ATTR_PTR(intr->ip);
  433. get_basic_attr( p, attr_name, offset, intr, script_error);
  434. if (attr_name!=REF_ATTR) {
  435. LOG(L_ERR,"ERROR:cpl_c:run_sub: invalid attr. %d (expected %d)in "
  436. "SUB node\n", attr_name, REF_ATTR);
  437. goto script_error;
  438. }
  439. /* make the jump */
  440. p = intr->ip - offset;
  441. /* check the destination pointer -> are we still inside the buffer ;-) */
  442. if (((char*)p)<intr->script.s) {
  443. LOG(L_ERR,"ERROR:cpl_c:run_sub: jump offset lower than the script "
  444. "beginning -> underflow!\n");
  445. goto script_error;
  446. }
  447. check_overflow_by_ptr( p+SIMPLE_NODE_SIZE(intr->ip), intr, script_error);
  448. /* check to see if we hit a subaction node */
  449. if ( NODE_TYPE(p)!=SUBACTION_NODE ) {
  450. LOG(L_ERR,"ERROR:cpl_c:run_sub: sub. jump hit a nonsubaction node!\n");
  451. goto script_error;
  452. }
  453. if ( NR_OF_ATTR(p)!=0 ) {
  454. LOG(L_ERR,"ERROR:cpl_c:run_sub: invalid subaction node reached "
  455. "(attrs=%d); expected (0)!\n",NR_OF_ATTR(p));
  456. goto script_error;
  457. }
  458. return get_first_child(p);
  459. script_error:
  460. return CPL_SCRIPT_ERROR;
  461. }
  462. /* UPDATED + CHECKED
  463. */
  464. static inline char *run_reject( struct cpl_interpreter *intr )
  465. {
  466. unsigned short attr_name;
  467. unsigned short status;
  468. unsigned short n;
  469. char *reason_s;
  470. char *p;
  471. int i;
  472. reason_s = (char*)UNDEF_CHAR;
  473. status = UNDEF_CHAR;
  474. /* sanity check */
  475. if (NR_OF_KIDS(intr->ip)!=0) {
  476. LOG(L_ERR,"ERROR:cpl_c:run_reject: REJECT node doesn't suppose to have "
  477. "any sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
  478. goto script_error;
  479. }
  480. for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
  481. get_basic_attr( p, attr_name, n, intr, script_error);
  482. switch (attr_name) {
  483. case STATUS_ATTR:
  484. status = n;
  485. break;
  486. case REASON_ATTR:
  487. get_str_attr( p, reason_s, n, intr, script_error,1);
  488. break;
  489. default:
  490. LOG(L_ERR,"ERROR:cpl_c:run_reject: unknown attribute "
  491. "(%d) in REJECT node\n",attr_name);
  492. goto script_error;
  493. }
  494. }
  495. if (status==UNDEF_CHAR) {
  496. LOG(L_ERR,"ERROR:cpl_c:run_reject: mandatory attribute STATUS "
  497. "not found\n");
  498. goto script_error;
  499. }
  500. if (status<400 || status>=700) {
  501. LOG(L_ERR,"ERROR:cpl_c:run_reject: bad attribute STATUS "
  502. "(%d)\n",status);
  503. goto script_error;
  504. }
  505. if (reason_s==(char*)UNDEF_CHAR ) {
  506. switch (status) {
  507. case 486:
  508. reason_s = "Busy Here";
  509. break;
  510. case 404:
  511. reason_s = "Not Found";
  512. break;
  513. case 603:
  514. reason_s = "Decline";
  515. break;
  516. case 500:
  517. reason_s = "Internal Server Error";
  518. break;
  519. default:
  520. reason_s = "Generic Error";
  521. }
  522. }
  523. /* if still stateless and FORCE_STATEFUL set -> build the transaction */
  524. if ( !(intr->flags&CPL_IS_STATEFUL) && intr->flags&CPL_FORCE_STATEFUL) {
  525. i = cpl_fct.tmb.t_newtran( intr->msg );
  526. if (i<0) {
  527. LOG(L_ERR,"ERROR:cpl-c:run_reject: failed to build new "
  528. "transaction!\n");
  529. goto runtime_error;
  530. } else if (i==0) {
  531. LOG(L_ERR,"ERROR:cpl-c:run_reject: processed INVITE is a "
  532. "retransmission!\n");
  533. /* instead of generating an error is better just to break the
  534. * script by returning EO_SCRIPT */
  535. return EO_SCRIPT;
  536. }
  537. intr->flags |= CPL_IS_STATEFUL;
  538. }
  539. /* send the reply */
  540. if ( intr->flags&CPL_IS_STATEFUL ) {
  541. /* reply statefully */
  542. i = cpl_fct.tmb.t_reply(intr->msg, (int)status, reason_s );
  543. } else {
  544. /* reply statelessly */
  545. i = cpl_fct.slb.zreply(intr->msg, status, reason_s );
  546. }
  547. if ( i!=1 ) {
  548. LOG(L_ERR,"ERROR:run_reject: unable to send reject reply!\n");
  549. goto runtime_error;
  550. }
  551. return EO_SCRIPT;
  552. runtime_error:
  553. return CPL_RUNTIME_ERROR;
  554. script_error:
  555. return CPL_SCRIPT_ERROR;
  556. }
  557. /* UPDATED + CHECKED
  558. */
  559. static inline char *run_redirect( struct cpl_interpreter *intr )
  560. {
  561. struct location *loc;
  562. struct lump_rpl *lump;
  563. unsigned short attr_name;
  564. unsigned short permanent;
  565. unsigned short n;
  566. char *p;
  567. str lump_str;
  568. char *cp;
  569. int i;
  570. permanent = NO_VAL;
  571. /* sanity check */
  572. if (NR_OF_KIDS(intr->ip)!=0) {
  573. LOG(L_ERR,"ERROR:cpl-c:run_redirect: REDIRECT node doesn't suppose "
  574. "to have any sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
  575. goto script_error;
  576. }
  577. /* read the attributes of the REDIRECT node*/
  578. for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
  579. get_basic_attr( p, attr_name, n, intr, script_error);
  580. switch (attr_name) {
  581. case PERMANENT_ATTR:
  582. if (n!=YES_VAL && n!=NO_VAL) {
  583. LOG(L_ERR,"ERROR:cpl-c:run_redirect: unsupported value (%d)"
  584. " in attribute PERMANENT for REDIRECT node",n);
  585. goto script_error;
  586. }
  587. permanent = n;
  588. break;
  589. default:
  590. LOG(L_ERR,"ERROR:run_redirect: unknown attribute "
  591. "(%d) in REDIRECT node\n",attr_name);
  592. goto script_error;
  593. }
  594. }
  595. /* build the lump for Contact header */
  596. lump_str.len = 9 /*"Contact: "*/;
  597. for(loc=intr->loc_set;loc;loc=loc->next)
  598. lump_str.len += 1/*"<"*/ + loc->addr.uri.len + 7/*">;q=x.x"*/ +
  599. 2*(loc->next!=0)/*" ,"*/;
  600. lump_str.len += CRLF_LEN;
  601. lump_str.s = pkg_malloc( lump_str.len );
  602. if(!lump_str.s) {
  603. LOG(L_ERR,"ERROR:cpl-c:run_redirect: out of pkg memory!\n");
  604. goto runtime_error;
  605. }
  606. cp = lump_str.s;
  607. memcpy( cp , "Contact: " , 9);
  608. cp += 9;
  609. for(loc=intr->loc_set;loc;loc=loc->next) {
  610. *(cp++) = '<';
  611. memcpy(cp,loc->addr.uri.s,loc->addr.uri.len);
  612. cp += loc->addr.uri.len;
  613. memcpy(cp,">;q=",4);
  614. cp += 4;
  615. *(cp++) = (loc->addr.priority!=10)?'0':'1';
  616. *(cp++) = '.';
  617. *(cp++) = '0'+(loc->addr.priority%10);
  618. if (loc->next) {
  619. *(cp++) = ' ';
  620. *(cp++) = ',';
  621. }
  622. }
  623. memcpy(cp,CRLF,CRLF_LEN);
  624. /* if still stateless and FORCE_STATEFUL set -> build the transaction */
  625. if ( !(intr->flags&CPL_IS_STATEFUL) && intr->flags&CPL_FORCE_STATEFUL) {
  626. i = cpl_fct.tmb.t_newtran( intr->msg );
  627. if (i<0) {
  628. LOG(L_ERR,"ERROR:cpl-c:run_redirect: failed to build new "
  629. "transaction!\n");
  630. pkg_free( lump_str.s );
  631. goto runtime_error;
  632. } else if (i==0) {
  633. LOG(L_ERR,"ERROR:cpl-c:run_redirect: processed INVITE is a "
  634. "retransmission!\n");
  635. /* instead of generating an error is better just to break the
  636. * script by returning EO_SCRIPT */
  637. pkg_free( lump_str.s );
  638. return EO_SCRIPT;
  639. }
  640. intr->flags |= CPL_IS_STATEFUL;
  641. }
  642. /* add the lump to the reply */
  643. lump = add_lump_rpl( intr->msg, lump_str.s , lump_str.len , LUMP_RPL_HDR);
  644. if(!lump) {
  645. LOG(L_ERR,"ERROR:cpl-c:run_redirect: unable to add lump_rpl! \n");
  646. pkg_free( lump_str.s );
  647. goto runtime_error;
  648. }
  649. /* send the reply */
  650. if ( intr->flags&CPL_IS_STATEFUL ) {
  651. /* reply statefully */
  652. if (permanent)
  653. i = cpl_fct.tmb.t_reply( intr->msg, (int)301, "Moved permanently");
  654. else
  655. i = cpl_fct.tmb.t_reply( intr->msg, (int)302, "Moved temporarily");
  656. } else {
  657. /* reply statelessly */
  658. if (permanent)
  659. i = cpl_fct.slb.zreply( intr->msg, 301, "Moved permanently");
  660. else
  661. i = cpl_fct.slb.zreply( intr->msg, 302, "Moved temporarily");
  662. }
  663. /* msg which I'm working on can be in private memory or is a clone into
  664. * shared memory (if I'm after a failed proxy); So, it's better to removed
  665. * by myself the lump that I added previously */
  666. unlink_lump_rpl( intr->msg, lump);
  667. free_lump_rpl( lump );
  668. if (i!=1) {
  669. LOG(L_ERR,"ERROR:cpl-c:run_redirect: unable to send "
  670. "redirect reply!\n");
  671. goto runtime_error;
  672. }
  673. return EO_SCRIPT;
  674. runtime_error:
  675. return CPL_RUNTIME_ERROR;
  676. script_error:
  677. return CPL_SCRIPT_ERROR;
  678. }
  679. /* UPDATED + CHECKED
  680. */
  681. static inline char *run_log( struct cpl_interpreter *intr )
  682. {
  683. char *p;
  684. unsigned short attr_name;
  685. unsigned short n;
  686. str name = STR_NULL;
  687. str comment = STR_NULL;
  688. str user;
  689. int i;
  690. /* sanity check */
  691. if (NR_OF_KIDS(intr->ip)>1) {
  692. LOG(L_ERR,"ERROR:cpl_c:run_log: LOG node suppose to have max one child"
  693. ", not %d!\n",NR_OF_KIDS(intr->ip));
  694. goto script_error;
  695. }
  696. /* is logging enabled? */
  697. if ( cpl_env.log_dir==0 )
  698. goto done;
  699. /* read the attributes of the LOG node*/
  700. p = ATTR_PTR(intr->ip);
  701. for( i=NR_OF_ATTR(intr->ip); i>0 ; i-- ) {
  702. get_basic_attr( p, attr_name, n, intr, script_error);
  703. switch (attr_name) {
  704. case NAME_ATTR:
  705. get_str_attr( p, name.s, n, intr, script_error,1);
  706. name.len = n;
  707. break;
  708. case COMMENT_ATTR:
  709. get_str_attr( p, comment.s, n, intr, script_error,1);
  710. comment.len = n;
  711. break;
  712. default:
  713. LOG(L_ERR,"ERROR:cpl_c:run_log: unknown attribute "
  714. "(%d) in LOG node\n",attr_name);
  715. goto script_error;
  716. }
  717. }
  718. if (comment.len==0) {
  719. LOG(L_NOTICE,"NOTICE:cpl_c:run_log: LOG node has no comment attr -> "
  720. "skipping\n");
  721. goto done;
  722. }
  723. user.len = intr->user.len + name.len + comment.len;
  724. /* duplicate the attrs in shm memory */
  725. user.s = p = (char*)shm_malloc( user.len );
  726. if (!user.s) {
  727. LOG(L_ERR,"ERROR:cpl_c:run_log: no more shm memory!\n");
  728. goto runtime_error;
  729. }
  730. /* copy the user name */
  731. memcpy( p, intr->user.s, intr->user.len);
  732. user.len = intr->user.len;
  733. p += intr->user.len;
  734. /* copy the log name */
  735. if (name.len) {
  736. memcpy( p, name.s, name.len );
  737. name.s = p;
  738. p += name.len;
  739. }
  740. /* copy the comment */
  741. memcpy( p, comment.s, comment.len);
  742. comment.s = p;
  743. /* send the command */
  744. write_cpl_cmd( CPL_LOG_CMD, &user, &name, &comment );
  745. done:
  746. return get_first_child(intr->ip);
  747. runtime_error:
  748. return CPL_RUNTIME_ERROR;
  749. script_error:
  750. return CPL_SCRIPT_ERROR;
  751. }
  752. /* UPDATED + CHECKED
  753. */
  754. static inline char *run_mail( struct cpl_interpreter *intr )
  755. {
  756. unsigned short attr_name;
  757. unsigned short n;
  758. char *p;
  759. str subject = STR_NULL;
  760. str body = STR_NULL;
  761. str to = STR_NULL;
  762. int i;
  763. /* sanity check */
  764. if (NR_OF_KIDS(intr->ip)>1) {
  765. LOG(L_ERR,"ERROR:cpl_c:run_mail: MAIL node suppose to have max one"
  766. " child, not %d!\n",NR_OF_KIDS(intr->ip));
  767. goto script_error;
  768. }
  769. /* read the attributes of the MAIL node*/
  770. for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
  771. get_basic_attr(p, attr_name, n, intr, script_error);
  772. switch (attr_name) {
  773. case TO_ATTR:
  774. get_str_attr(p, to.s, n, intr, script_error,0);
  775. to.len = n;
  776. break;
  777. case SUBJECT_ATTR:
  778. get_str_attr(p, subject.s, n, intr, script_error,0);
  779. subject.len = n;
  780. break;
  781. case BODY_ATTR:
  782. get_str_attr(p, body.s, n, intr, script_error,0);
  783. body.len = n;
  784. break;
  785. default:
  786. LOG(L_ERR,"ERROR:run_mail: unknown attribute "
  787. "(%d) in MAIL node\n",attr_name);
  788. goto script_error;
  789. }
  790. }
  791. if (to.len==0) {
  792. LOG(L_ERR,"ERROR:cpl_c:run_mail: email has an empty TO hdr!\n");
  793. goto script_error;
  794. }
  795. if (body.len==0 && subject.len==0) {
  796. LOG(L_WARN,"WARNING:cpl_c:run_mail: I refuse to send email with no "
  797. "body and no subject -> skipping...\n");
  798. goto done;
  799. }
  800. /* duplicate the attrs in shm memory */
  801. p = (char*)shm_malloc( to.len + subject.len + body.len );
  802. if (!p) {
  803. LOG(L_ERR,"ERROR:cpl_c:run_mail: no more shm memory!\n");
  804. goto runtime_error;
  805. }
  806. /* copy the TO */
  807. memcpy( p, to.s, to.len );
  808. to.s = p;
  809. p += to.len;
  810. /* copy the subject */
  811. if (subject.len) {
  812. memcpy( p, subject.s, subject.len );
  813. subject.s = p;
  814. p += subject.len;
  815. }
  816. /* copy the body */
  817. if (body.len) {
  818. memcpy( p, body.s, body.len );
  819. body.s = p;
  820. p += body.len;
  821. }
  822. /* send the command */
  823. write_cpl_cmd( CPL_MAIL_CMD, &to, &subject, &body);
  824. done:
  825. return get_first_child(intr->ip);
  826. runtime_error:
  827. return CPL_RUNTIME_ERROR;
  828. script_error:
  829. return CPL_SCRIPT_ERROR;
  830. }
  831. static inline int run_default( struct cpl_interpreter *intr )
  832. {
  833. if (!(intr->flags&CPL_PROXY_DONE)) {
  834. /* no signaling operations */
  835. if ( !(intr->flags&CPL_LOC_SET_MODIFIED) ) {
  836. /* no location modifications */
  837. if (intr->loc_set==0 ) {
  838. /* case 1 : no location modifications or signaling operations
  839. * performed, location set empty ->
  840. * Look up the user's location through whatever mechanism the
  841. * server would use if no CPL script were in effect */
  842. return SCRIPT_DEFAULT;
  843. } else {
  844. /* case 2 : no location modifications or signaling operations
  845. * performed, location set non-empty: (This can only happen
  846. * for outgoing calls.) ->
  847. * Proxy the call to the address in the location set.
  848. * With other words, let ser to continue processing the
  849. * request as nothing happened */
  850. return SCRIPT_DEFAULT;
  851. }
  852. } else {
  853. /* case 3 : location modifications performed, no signaling
  854. * operations ->
  855. * Proxy the call to the addresses in the location set */
  856. if (!cpl_proxy_to_loc_set(intr->msg,&(intr->loc_set),intr->flags))
  857. return SCRIPT_END;
  858. return SCRIPT_RUN_ERROR;
  859. }
  860. } else {
  861. /* case 4 : proxy operation previously taken -> return whatever the
  862. * "best" response is of all accumulated responses to the call to this
  863. * point, according to the rules of the underlying signaling
  864. * protocol. */
  865. /* we will let ser to choose and forward one of the replies -> for this
  866. * nothing must be done */
  867. return SCRIPT_END;
  868. }
  869. /*return SCRIPT_RUN_ERROR;*/
  870. }
  871. /* include all inline functions for processing the switches */
  872. #include "cpl_switches.h"
  873. /* include inline function for running proxy node */
  874. #include "cpl_proxy.h"
  875. int cpl_run_script( struct cpl_interpreter *intr )
  876. {
  877. char *new_ip;
  878. do {
  879. check_overflow_by_offset( SIMPLE_NODE_SIZE(intr->ip), intr, error);
  880. switch ( NODE_TYPE(intr->ip) ) {
  881. case CPL_NODE:
  882. DBG("DEBUG:cpl_run_script: processing CPL node \n");
  883. new_ip = run_cpl_node( intr ); /*UPDATED&TESTED*/
  884. break;
  885. case ADDRESS_SWITCH_NODE:
  886. DBG("DEBUG:cpl_run_script: processing address-switch node\n");
  887. new_ip = run_address_switch( intr ); /*UPDATED&TESTED*/
  888. break;
  889. case STRING_SWITCH_NODE:
  890. DBG("DEBUG:cpl_run_script: processing string-switch node\n");
  891. new_ip = run_string_switch( intr ); /*UPDATED&TESTED*/
  892. break;
  893. case PRIORITY_SWITCH_NODE:
  894. DBG("DEBUG:cpl_run_script: processing priority-switch node\n");
  895. new_ip = run_priority_switch( intr ); /*UPDATED&TESTED*/
  896. break;
  897. case TIME_SWITCH_NODE:
  898. DBG("DEBUG:cpl_run_script: processing time-switch node\n");
  899. new_ip = run_time_switch( intr ); /*UPDATED&TESTED*/
  900. break;
  901. case LANGUAGE_SWITCH_NODE:
  902. DBG("DEBUG:cpl_run_script: processing language-switch node\n");
  903. new_ip = run_language_switch( intr ); /*UPDATED&TESTED*/
  904. break;
  905. case LOOKUP_NODE:
  906. DBG("DEBUG:cpl_run_script: processing lookup node\n");
  907. new_ip = run_lookup( intr ); /*UPDATED&TESTED*/
  908. break;
  909. case LOCATION_NODE:
  910. DBG("DEBUG:cpl_run_script: processing location node\n");
  911. new_ip = run_location( intr ); /*UPDATED&TESTED*/
  912. break;
  913. case REMOVE_LOCATION_NODE:
  914. DBG("DEBUG:cpl_run_script: processing remove_location node\n");
  915. new_ip = run_remove_location( intr ); /*UPDATED&TESTED*/
  916. break;
  917. case PROXY_NODE:
  918. DBG("DEBUG:cpl_run_script: processing proxy node\n");
  919. new_ip = run_proxy( intr );/*UPDATED&TESTED*/
  920. break;
  921. case REJECT_NODE:
  922. DBG("DEBUG:cpl_run_script: processing reject node\n");
  923. new_ip = run_reject( intr ); /*UPDATED&TESTED*/
  924. break;
  925. case REDIRECT_NODE:
  926. DBG("DEBUG:cpl_run_script: processing redirect node\n");
  927. new_ip = run_redirect( intr ); /*UPDATED&TESTED*/
  928. break;
  929. case LOG_NODE:
  930. DBG("DEBUG:cpl_run_script: processing log node\n");
  931. new_ip = run_log( intr ); /*UPDATED&TESTED*/
  932. break;
  933. case MAIL_NODE:
  934. DBG("DEBUG:cpl_run_script: processing mail node\n");
  935. new_ip = run_mail( intr ); /*UPDATED&TESTED*/
  936. break;
  937. case SUB_NODE:
  938. DBG("DEBUG:cpl_run_script: processing sub node\n");
  939. new_ip = run_sub( intr ); /*UPDATED&TESTED*/
  940. break;
  941. default:
  942. LOG(L_ERR,"ERROR:cpl_run_script: unknown type node (%d)\n",
  943. NODE_TYPE(intr->ip));
  944. goto error;
  945. }
  946. if (new_ip==CPL_RUNTIME_ERROR) {
  947. LOG(L_ERR,"ERROR:cpl_c:cpl_run_script: runtime error\n");
  948. return SCRIPT_RUN_ERROR;
  949. } else if (new_ip==CPL_SCRIPT_ERROR) {
  950. LOG(L_ERR,"ERROR:cpl_c:cpl_run_script: script error\n");
  951. return SCRIPT_FORMAT_ERROR;
  952. } else if (new_ip==DEFAULT_ACTION) {
  953. DBG("DEBUG:cpl_c:cpl_run_script: running default action\n");
  954. return run_default(intr);
  955. } else if (new_ip==EO_SCRIPT) {
  956. DBG("DEBUG:cpl_c:cpl_run_script: script interpretation done!\n");
  957. return SCRIPT_END;
  958. } else if (new_ip==CPL_TO_CONTINUE) {
  959. DBG("DEBUG:cpl_c:cpl_run_script: done for the moment; waiting "
  960. "after signaling!\n");
  961. return SCRIPT_TO_BE_CONTINUED;
  962. }
  963. /* move to the new instruction */
  964. intr->ip = new_ip;
  965. }while(1);
  966. error:
  967. return SCRIPT_FORMAT_ERROR;
  968. }