cpl_proxy.h 17 KB

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