cpl_proxy.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2001-2003 FhG Fokus
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * Kamailio 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. * Kamailio is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * History:
  23. * -------
  24. * 2003-07-29: file created (bogdan)
  25. * 2004-06-14: flag CPL_IS_STATEFUL is set now immediately after the
  26. * transaction is created (bogdan)
  27. */
  28. #include "../../modules/tm/h_table.h"
  29. #include "../../parser/contact/parse_contact.h"
  30. #define duplicate_str( _orig_ , _new_ ) \
  31. do {\
  32. (_new_) = (str*)shm_malloc(sizeof(str)+(_orig_)->len);\
  33. if (!(_new_)) goto mem_error;\
  34. (_new_)->len = (_orig_)->len;\
  35. (_new_)->s = (char*)((_new_))+sizeof(str);\
  36. memcpy((_new_)->s,(_orig_)->s,(_orig_)->len);\
  37. } while(0)
  38. #define search_and_duplicate_hdr( _intr_ , _field_ , _name_ , _sfoo_ ) \
  39. do {\
  40. if (!(_intr_)->_field_) {\
  41. if (!(_intr_)->msg->_field_) { \
  42. if (parse_headers((_intr_)->msg,_name_,0)==-1) {\
  43. LM_ERR("bad %llx hdr\n",_name_);\
  44. goto runtime_error;\
  45. } else if ( !(_intr_)->msg->_field_) {\
  46. (_intr_)->_field_ = STR_NOT_FOUND;\
  47. } else {\
  48. (_sfoo_) = &((_intr_)->msg->_field_->body);\
  49. duplicate_str( (_sfoo_) , (_intr_)->_field_ );\
  50. }\
  51. } else {\
  52. (_sfoo_) = &((_intr_)->msg->_field_->body);\
  53. duplicate_str( (_sfoo_) , (_intr_)->_field_ );\
  54. }\
  55. } else {\
  56. (_sfoo_) = (_intr_)->_field_;\
  57. duplicate_str( (_sfoo_) , (_intr_)->_field_ );\
  58. }\
  59. }while(0)
  60. static inline int parse_q(str *q, unsigned int *prio)
  61. {
  62. if (q->s[0]=='0')
  63. *prio=0;
  64. else if (q->s[0]=='1')
  65. *prio=10;
  66. else
  67. goto error;
  68. if (q->s[1]!='.')
  69. goto error;
  70. if (q->s[2]<'0' || q->s[2]>'9')
  71. goto error;
  72. *prio += q->s[2] - '0';
  73. if (*prio>10)
  74. goto error;
  75. return 0;
  76. error:
  77. LM_ERR("bad q param <%.*s>\n",q->len,q->s);
  78. return -1;
  79. }
  80. static inline int add_contacts_to_loc_set(struct sip_msg* msg,
  81. struct location **loc_set)
  82. {
  83. struct sip_uri uri;
  84. struct contact *contacts;
  85. unsigned int prio;
  86. /* we need to have the contact header */
  87. if (msg->contact==0) {
  88. /* find and parse the Contact header */
  89. if ((parse_headers(msg, HDR_CONTACT_F, 0)==-1) || (msg->contact==0)) {
  90. LM_ERR("error parsing or no Contact hdr found!\n");
  91. goto error;
  92. }
  93. }
  94. /* extract from contact header the all the addresses */
  95. if (parse_contact( msg->contact )!=0) {
  96. LM_ERR("unable to parse Contact hdr!\n");
  97. goto error;
  98. }
  99. /* in contact hdr, in parsed attr, we should have a list of contacts */
  100. if ( msg->contact->parsed ) {
  101. contacts = ((struct contact_body*)msg->contact->parsed)->contacts;
  102. for( ; contacts ; contacts=contacts->next) {
  103. /* check if the contact is a valid sip uri */
  104. if (parse_uri( contacts->uri.s, contacts->uri.len , &uri)!=0) {
  105. continue;
  106. }
  107. /* convert the q param to int value (if any) */
  108. if (contacts->q) {
  109. if (parse_q( &(contacts->q->body), &prio )!=0)
  110. continue;
  111. } else {
  112. prio = 10; /* set default to minimum */
  113. }
  114. /* add the uri to location set */
  115. if (add_location(loc_set,&contacts->uri,0,prio,CPL_LOC_DUPL)!=0) {
  116. LM_ERR("unable to add <%.*s>\n",
  117. contacts->uri.len,contacts->uri.s);
  118. }
  119. }
  120. }
  121. return 0;
  122. error:
  123. return -1;
  124. }
  125. static void reply_callback( struct cell* t, int type, struct tmcb_params* ps)
  126. {
  127. struct cpl_interpreter *intr = (struct cpl_interpreter*)(*(ps->param));
  128. struct location *loc = 0;
  129. int rez;
  130. if (intr==0) {
  131. LM_WARN("param=0 for callback %d, transaction=%p \n",type,t);
  132. return;
  133. }
  134. if (type&TMCB_RESPONSE_OUT) {
  135. /* the purpose of the final reply is to trash down the interpreter
  136. * structure! it's the safest place to do that, since this callback
  137. * it's called only once per transaction for final codes (>=200) ;-) */
  138. if (ps->code>=200) {
  139. LM_DBG("code=%d, final reply received\n", ps->code);
  140. /* CPL interpretation done, call established -> destroy */
  141. free_cpl_interpreter( intr );
  142. /* set to zero the param callback*/
  143. *(ps->param) = 0;
  144. }
  145. return;
  146. } else if (! (type&TMCB_ON_FAILURE)) {
  147. LM_ERR("unknown type %d\n",type);
  148. goto exit;
  149. }
  150. LM_DBG("negativ reply received\n");
  151. intr->flags |= CPL_PROXY_DONE;
  152. intr->msg = ps->req;
  153. /* is the negative reply triggered by a cancel from UAC side? */
  154. if (was_cancelled(t)) {
  155. /* stop whole interpretation */
  156. return;
  157. }
  158. /* if it's a redirect-> do I have to added to the location set ? */
  159. if (intr->proxy.recurse && (ps->code)/100==3) {
  160. LM_DBG("recurse level %d processing..\n",intr->proxy.recurse);
  161. intr->proxy.recurse--;
  162. /* get the locations from the Contact */
  163. add_contacts_to_loc_set( ps->rpl, &(intr->loc_set));
  164. switch (intr->proxy.ordering) {
  165. case SEQUENTIAL_VAL:
  166. /* update the last_to_proxy to last location from set */
  167. if (intr->proxy.last_to_proxy==0) {
  168. /* the pointer went through entire old set -> set it to the
  169. * updated set, from the beginning */
  170. if (intr->loc_set==0)
  171. /* the updated set is also empty -> proxy ended */
  172. break;
  173. intr->proxy.last_to_proxy = intr->loc_set;
  174. }
  175. while(intr->proxy.last_to_proxy->next)
  176. intr->proxy.last_to_proxy=intr->proxy.last_to_proxy->next;
  177. break;
  178. case PARALLEL_VAL:
  179. /* push the whole new location set to be proxy */
  180. intr->proxy.last_to_proxy = intr->loc_set;
  181. break;
  182. case FIRSTONLY_VAL:
  183. intr->proxy.last_to_proxy = 0;
  184. break;
  185. }
  186. }
  187. /* the current proxying failed -> do I have another location to try ?
  188. * This applies only for SERIAL forking or if RECURSE is set */
  189. if (intr->proxy.last_to_proxy && !(no_new_branches(t)) ) {
  190. /* continue proxying */
  191. LM_DBG("resuming proxying....\n");
  192. switch (intr->proxy.ordering) {
  193. case PARALLEL_VAL:
  194. /* I get here only if I got a 3xx and RECURSE in on ->
  195. * forward to all location from location set */
  196. intr->proxy.last_to_proxy = 0;
  197. cpl_proxy_to_loc_set(intr->msg,&(intr->loc_set),intr->flags );
  198. break;
  199. case SEQUENTIAL_VAL:
  200. /* place a new branch to the next location from loc. set*/
  201. loc = remove_first_location( &(intr->loc_set) );
  202. /*print_location_set(intr->loc_set);*/
  203. /* update (if necessary) the last_to_proxy location */
  204. if (intr->proxy.last_to_proxy==loc)
  205. intr->proxy.last_to_proxy = 0;
  206. cpl_proxy_to_loc_set(intr->msg,&loc,intr->flags );
  207. break;
  208. default:
  209. LM_CRIT("unexpected ordering found "
  210. "when continuing proxying (%d)\n",intr->proxy.ordering);
  211. goto exit;
  212. }
  213. /* nothing more to be done */
  214. return;
  215. } else {
  216. /* done with proxying.... -> process the final response */
  217. LM_DBG("final_reply: got a final %d\n",ps->code);
  218. intr->ip = 0;
  219. if (ps->code==486 || ps->code==600) {
  220. /* busy response */
  221. intr->ip = intr->proxy.busy;
  222. } else if (ps->code==408) {
  223. /* request timeout -> no response */
  224. intr->ip = intr->proxy.noanswer;
  225. } else if (((ps->code)/100)==3) {
  226. /* redirection */
  227. /* add to the location list all the addresses from Contact */
  228. add_contacts_to_loc_set( ps->rpl, &(intr->loc_set));
  229. print_location_set( intr->loc_set );
  230. intr->ip = intr->proxy.redirect;
  231. } else {
  232. /* generic failure */
  233. intr->ip = intr->proxy.failure;
  234. }
  235. if (intr->ip==0)
  236. intr->ip = (intr->proxy.default_)?
  237. intr->proxy.default_:DEFAULT_ACTION;
  238. if (intr->ip!=DEFAULT_ACTION)
  239. intr->ip = get_first_child( intr->ip );
  240. if( intr->ip==DEFAULT_ACTION)
  241. rez = run_default(intr);
  242. else
  243. rez = cpl_run_script(intr);
  244. switch ( rez ) {
  245. case SCRIPT_END:
  246. /* we don't need to free the interpreter here since it will
  247. * be freed in the final_reply callback */
  248. case SCRIPT_TO_BE_CONTINUED:
  249. return;
  250. case SCRIPT_RUN_ERROR:
  251. case SCRIPT_FORMAT_ERROR:
  252. goto exit;
  253. default:
  254. LM_CRIT("improper result %d\n",
  255. rez);
  256. goto exit;
  257. }
  258. }
  259. exit:
  260. /* in case of error the default response chosen by ser at the last
  261. * proxying will be forwarded to the UAC */
  262. free_cpl_interpreter( intr );
  263. /* set to zero the param callback*/
  264. *(ps->param) = 0;
  265. return;
  266. }
  267. static inline char *run_proxy( struct cpl_interpreter *intr )
  268. {
  269. unsigned short attr_name;
  270. unsigned short n;
  271. int_str is_val;
  272. char *kid;
  273. char *p;
  274. int i;
  275. str *s;
  276. struct location *loc;
  277. intr->proxy.ordering = PARALLEL_VAL;
  278. intr->proxy.recurse = (unsigned short)cpl_env.proxy_recurse;
  279. /* identify the attributes */
  280. for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
  281. get_basic_attr( p, attr_name, n, intr, script_error);
  282. switch (attr_name) {
  283. case TIMEOUT_ATTR:
  284. if (cpl_env.timer_avp.n || cpl_env.timer_avp.s.s) {
  285. is_val.n = n;
  286. if ( add_avp( cpl_env.timer_avp_type,
  287. cpl_env.timer_avp, is_val)<0) {
  288. LM_ERR("unable to set timer AVP\n");
  289. /* continue */
  290. }
  291. }
  292. break;
  293. case RECURSE_ATTR:
  294. switch (n) {
  295. case NO_VAL:
  296. intr->proxy.recurse = 0;
  297. break;
  298. case YES_VAL:
  299. /* already set as default */
  300. break;
  301. default:
  302. LM_ERR("invalid value (%u) found"
  303. " for attr. RECURSE in PROXY node!\n",n);
  304. goto script_error;
  305. }
  306. break;
  307. case ORDERING_ATTR:
  308. if (n!=PARALLEL_VAL && n!=SEQUENTIAL_VAL && n!=FIRSTONLY_VAL){
  309. LM_ERR("invalid value (%u) found"
  310. " for attr. ORDERING in PROXY node!\n",n);
  311. goto script_error;
  312. }
  313. intr->proxy.ordering = n;
  314. break;
  315. default:
  316. LM_ERR("unknown attribute (%d) in"
  317. "PROXY node\n",attr_name);
  318. goto script_error;
  319. }
  320. }
  321. intr->proxy.busy = intr->proxy.noanswer = 0;
  322. intr->proxy.redirect = intr->proxy.failure = intr->proxy.default_ = 0;
  323. /* this is quite an "expensive" node to run, so let's make some checking
  324. * before getting deeply into it */
  325. for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
  326. kid = intr->ip + KID_OFFSET(intr->ip,i);
  327. check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
  328. switch ( NODE_TYPE(kid) ) {
  329. case BUSY_NODE :
  330. intr->proxy.busy = kid;
  331. break;
  332. case NOANSWER_NODE:
  333. intr->proxy.noanswer = kid;
  334. break;
  335. case REDIRECTION_NODE:
  336. intr->proxy.redirect = kid;
  337. break;
  338. case FAILURE_NODE:
  339. intr->proxy.failure = kid;
  340. break;
  341. case DEFAULT_NODE:
  342. intr->proxy.default_ = kid;
  343. break;
  344. default:
  345. LM_ERR("unknown output node type"
  346. " (%d) for PROXY node\n",NODE_TYPE(kid));
  347. goto script_error;
  348. }
  349. }
  350. /* if the location set if empty, I will go directly on failure/default */
  351. if (intr->loc_set==0) {
  352. LM_DBG("location set found empty -> going on "
  353. "failure/default branch\n");
  354. if (intr->proxy.failure)
  355. return get_first_child(intr->proxy.failure);
  356. else if (intr->proxy.default_)
  357. return get_first_child(intr->proxy.default_);
  358. else return DEFAULT_ACTION;
  359. }
  360. /* if it's the first execution of a proxy node, force parsing of the needed
  361. * headers and duplicate them in shared memory */
  362. if (!(intr->flags&CPL_PROXY_DONE)) {
  363. /* user name is already in shared memory */
  364. /* requested URI - mandatory in SIP msg (cannot be STR_NOT_FOUND) */
  365. s = GET_RURI( intr->msg );
  366. duplicate_str( s , intr->ruri );
  367. intr->flags |= CPL_RURI_DUPLICATED;
  368. /* TO header - mandatory in SIP msg (cannot be STR_NOT_FOUND) */
  369. if (!intr->to) {
  370. if (!intr->msg->to &&
  371. (parse_headers(intr->msg,HDR_TO_F,0)==-1 || !intr->msg->to)) {
  372. LM_ERR("bad msg or missing TO header\n");
  373. goto runtime_error;
  374. }
  375. s = &(get_to(intr->msg)->uri);
  376. } else {
  377. s = intr->to;
  378. }
  379. duplicate_str( s , intr->to );
  380. intr->flags |= CPL_TO_DUPLICATED;
  381. /* FROM header - mandatory in SIP msg (cannot be STR_NOT_FOUND) */
  382. if (!intr->from) {
  383. if (parse_from_header( intr->msg )<0)
  384. goto runtime_error;
  385. s = &(get_from(intr->msg)->uri);
  386. } else {
  387. s = intr->from;
  388. }
  389. duplicate_str( s , intr->from );
  390. intr->flags |= CPL_FROM_DUPLICATED;
  391. /* SUBJECT header - optional in SIP msg (can be STR_NOT_FOUND) */
  392. if (intr->subject!=STR_NOT_FOUND) {
  393. search_and_duplicate_hdr(intr,subject,HDR_SUBJECT_F,s);
  394. if (intr->subject!=STR_NOT_FOUND)
  395. intr->flags |= CPL_SUBJECT_DUPLICATED;
  396. }
  397. /* ORGANIZATION header - optional in SIP msg (can be STR_NOT_FOUND) */
  398. if ( intr->organization!=STR_NOT_FOUND) {
  399. search_and_duplicate_hdr(intr,organization,HDR_ORGANIZATION_F,s);
  400. if ( intr->organization!=STR_NOT_FOUND)
  401. intr->flags |= CPL_ORGANIZATION_DUPLICATED;
  402. }
  403. /* USER_AGENT header - optional in SIP msg (can be STR_NOT_FOUND) */
  404. if (intr->user_agent!=STR_NOT_FOUND) {
  405. search_and_duplicate_hdr(intr,user_agent,HDR_USERAGENT_F,s);
  406. if (intr->user_agent!=STR_NOT_FOUND)
  407. intr->flags |= CPL_USERAGENT_DUPLICATED;
  408. }
  409. /* ACCEPT_LANGUAGE header - optional in SIP msg
  410. * (can be STR_NOT_FOUND) */
  411. if (intr->accept_language!=STR_NOT_FOUND) {
  412. search_and_duplicate_hdr(intr,accept_language,
  413. HDR_ACCEPTLANGUAGE_F,s);
  414. if (intr->accept_language!=STR_NOT_FOUND)
  415. intr->flags |= CPL_ACCEPTLANG_DUPLICATED;
  416. }
  417. /* PRIORITY header - optional in SIP msg (can be STR_NOT_FOUND) */
  418. if (intr->priority!=STR_NOT_FOUND) {
  419. search_and_duplicate_hdr(intr,priority,HDR_PRIORITY_F,s);
  420. if (intr->priority!=STR_NOT_FOUND)
  421. intr->flags |= CPL_PRIORITY_DUPLICATED;
  422. }
  423. /* now is the first time doing proxy, so I can still be stateless;
  424. * as proxy is done all the time stateful, I have to switch from
  425. * stateless to stateful if necessary. */
  426. if ( !(intr->flags&CPL_IS_STATEFUL) ) {
  427. i = cpl_fct.tmb.t_newtran( intr->msg );
  428. if (i<0) {
  429. LM_ERR("failed to build new transaction!\n");
  430. goto runtime_error;
  431. } else if (i==0) {
  432. LM_ERR("processed INVITE is a retransmission!\n");
  433. /* instead of generating an error is better just to break the
  434. * script by returning EO_SCRIPT */
  435. return EO_SCRIPT;
  436. }
  437. intr->flags |= CPL_IS_STATEFUL;
  438. }
  439. /* as I am interested in getting the responses back - I need to install
  440. * some callback functions for replies */
  441. if (cpl_fct.tmb.register_tmcb(intr->msg,0,
  442. TMCB_ON_FAILURE|TMCB_RESPONSE_OUT,reply_callback,(void*)intr,0) <= 0 ) {
  443. LM_ERR("failed to register TMCB_RESPONSE_OUT callback\n");
  444. goto runtime_error;
  445. }
  446. }
  447. switch (intr->proxy.ordering) {
  448. case FIRSTONLY_VAL:
  449. /* forward the request only to the first address from loc. set */
  450. /* location set cannot be empty -> was checked before */
  451. loc = remove_first_location( &(intr->loc_set) );
  452. intr->proxy.last_to_proxy = 0;
  453. /* set the new ip before proxy -> otherwise race cond with rpls */
  454. intr->ip = CPL_TO_CONTINUE;
  455. if (cpl_proxy_to_loc_set(intr->msg,&loc,intr->flags )==-1)
  456. goto runtime_error;
  457. break;
  458. case PARALLEL_VAL:
  459. /* forward to all location from location set */
  460. intr->proxy.last_to_proxy = 0;
  461. /* set the new ip before proxy -> otherwise race cond with rpls */
  462. intr->ip = CPL_TO_CONTINUE;
  463. if (cpl_proxy_to_loc_set(intr->msg,&(intr->loc_set),intr->flags)
  464. ==-1)
  465. goto runtime_error;
  466. break;
  467. case SEQUENTIAL_VAL:
  468. /* forward the request one at the time to all addresses from
  469. * loc. set; location set cannot be empty -> was checked before */
  470. /* use the first location from set */
  471. loc = remove_first_location( &(intr->loc_set) );
  472. /* set as the last_to_proxy the last location from set */
  473. intr->proxy.last_to_proxy = intr->loc_set;
  474. while (intr->proxy.last_to_proxy&&intr->proxy.last_to_proxy->next)
  475. intr->proxy.last_to_proxy = intr->proxy.last_to_proxy->next;
  476. /* set the new ip before proxy -> otherwise race cond with rpls */
  477. intr->ip = CPL_TO_CONTINUE;
  478. if (cpl_proxy_to_loc_set(intr->msg,&loc,intr->flags)==-1)
  479. goto runtime_error;
  480. break;
  481. }
  482. return CPL_TO_CONTINUE;
  483. script_error:
  484. return CPL_SCRIPT_ERROR;
  485. mem_error:
  486. LM_ERR("no more free shm memory\n");
  487. runtime_error:
  488. return CPL_RUNTIME_ERROR;
  489. }