00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "../../modules/tm/h_table.h"
00030 #include "../../parser/contact/parse_contact.h"
00031
00032
00033 #define duplicate_str( _orig_ , _new_ ) \
00034 do {\
00035 (_new_) = (str*)shm_malloc(sizeof(str)+(_orig_)->len);\
00036 if (!(_new_)) goto mem_error;\
00037 (_new_)->len = (_orig_)->len;\
00038 (_new_)->s = (char*)((_new_))+sizeof(str);\
00039 memcpy((_new_)->s,(_orig_)->s,(_orig_)->len);\
00040 } while(0)
00041
00042 #define search_and_duplicate_hdr( _intr_ , _field_ , _name_ , _sfoo_ ) \
00043 do {\
00044 if (!(_intr_)->_field_) {\
00045 if (!(_intr_)->msg->_field_) { \
00046 if (parse_headers((_intr_)->msg,_name_,0)==-1) {\
00047 LM_ERR("bad %llx hdr\n",_name_);\
00048 goto runtime_error;\
00049 } else if ( !(_intr_)->msg->_field_) {\
00050 (_intr_)->_field_ = STR_NOT_FOUND;\
00051 } else {\
00052 (_sfoo_) = &((_intr_)->msg->_field_->body);\
00053 duplicate_str( (_sfoo_) , (_intr_)->_field_ );\
00054 }\
00055 } else {\
00056 (_sfoo_) = &((_intr_)->msg->_field_->body);\
00057 duplicate_str( (_sfoo_) , (_intr_)->_field_ );\
00058 }\
00059 } else {\
00060 (_sfoo_) = (_intr_)->_field_;\
00061 duplicate_str( (_sfoo_) , (_intr_)->_field_ );\
00062 }\
00063 }while(0)
00064
00065
00066
00067 static inline int parse_q(str *q, unsigned int *prio)
00068 {
00069 if (q->s[0]=='0')
00070 *prio=0;
00071 else if (q->s[0]=='1')
00072 *prio=10;
00073 else
00074 goto error;
00075 if (q->s[1]!='.')
00076 goto error;
00077 if (q->s[2]<'0' || q->s[2]>'9')
00078 goto error;
00079 *prio += q->s[2] - '0';
00080 if (*prio>10)
00081 goto error;
00082
00083 return 0;
00084 error:
00085 LM_ERR("bad q param <%.*s>\n",q->len,q->s);
00086 return -1;
00087 }
00088
00089
00090
00091 static inline int add_contacts_to_loc_set(struct sip_msg* msg,
00092 struct location **loc_set)
00093 {
00094 struct sip_uri uri;
00095 struct contact *contacts;
00096 unsigned int prio;
00097
00098
00099 if (msg->contact==0) {
00100
00101 if ((parse_headers(msg, HDR_CONTACT_F, 0)==-1) || (msg->contact==0)) {
00102 LM_ERR("error parsing or no Contact hdr found!\n");
00103 goto error;
00104 }
00105 }
00106
00107
00108 if (parse_contact( msg->contact )!=0) {
00109 LM_ERR("unable to parse Contact hdr!\n");
00110 goto error;
00111 }
00112
00113
00114 if ( msg->contact->parsed ) {
00115 contacts = ((struct contact_body*)msg->contact->parsed)->contacts;
00116 for( ; contacts ; contacts=contacts->next) {
00117
00118 if (parse_uri( contacts->uri.s, contacts->uri.len , &uri)!=0) {
00119 continue;
00120 }
00121
00122 if (contacts->q) {
00123 if (parse_q( &(contacts->q->body), &prio )!=0)
00124 continue;
00125 } else {
00126 prio = 10;
00127 }
00128
00129 if (add_location(loc_set,&contacts->uri,0,prio,CPL_LOC_DUPL)!=0) {
00130 LM_ERR("unable to add <%.*s>\n",
00131 contacts->uri.len,contacts->uri.s);
00132 }
00133 }
00134 }
00135
00136 return 0;
00137 error:
00138 return -1;
00139 }
00140
00141
00142
00143 static void reply_callback( struct cell* t, int type, struct tmcb_params* ps)
00144 {
00145 struct cpl_interpreter *intr = (struct cpl_interpreter*)(*(ps->param));
00146 struct location *loc = 0;
00147 int rez;
00148
00149 if (intr==0) {
00150 LM_WARN("param=0 for callback %d, transaction=%p \n",type,t);
00151 return;
00152 }
00153
00154 if (type&TMCB_RESPONSE_OUT) {
00155
00156
00157
00158 if (ps->code>=200) {
00159 LM_DBG("code=%d, final reply received\n", ps->code);
00160
00161 free_cpl_interpreter( intr );
00162
00163 *(ps->param) = 0;
00164 }
00165 return;
00166 } else if (! (type&TMCB_ON_FAILURE)) {
00167 LM_ERR("unknown type %d\n",type);
00168 goto exit;
00169 }
00170
00171 LM_DBG("negativ reply received\n");
00172
00173 intr->flags |= CPL_PROXY_DONE;
00174 intr->msg = ps->req;
00175
00176
00177 if (was_cancelled(t)) {
00178
00179 return;
00180 }
00181
00182
00183 if (intr->proxy.recurse && (ps->code)/100==3) {
00184 LM_DBG("recurse level %d processing..\n",intr->proxy.recurse);
00185 intr->proxy.recurse--;
00186
00187 add_contacts_to_loc_set( ps->rpl, &(intr->loc_set));
00188 switch (intr->proxy.ordering) {
00189 case SEQUENTIAL_VAL:
00190
00191 if (intr->proxy.last_to_proxy==0) {
00192
00193
00194 if (intr->loc_set==0)
00195
00196 break;
00197 intr->proxy.last_to_proxy = intr->loc_set;
00198 }
00199 while(intr->proxy.last_to_proxy->next)
00200 intr->proxy.last_to_proxy=intr->proxy.last_to_proxy->next;
00201 break;
00202 case PARALLEL_VAL:
00203
00204 intr->proxy.last_to_proxy = intr->loc_set;
00205 break;
00206 case FIRSTONLY_VAL:
00207 intr->proxy.last_to_proxy = 0;
00208 break;
00209 }
00210 }
00211
00212
00213
00214 if (intr->proxy.last_to_proxy && !(no_new_branches(t)) ) {
00215
00216 LM_DBG("resuming proxying....\n");
00217 switch (intr->proxy.ordering) {
00218 case PARALLEL_VAL:
00219
00220
00221 intr->proxy.last_to_proxy = 0;
00222 cpl_proxy_to_loc_set(intr->msg,&(intr->loc_set),intr->flags );
00223 break;
00224 case SEQUENTIAL_VAL:
00225
00226 loc = remove_first_location( &(intr->loc_set) );
00227
00228
00229 if (intr->proxy.last_to_proxy==loc)
00230 intr->proxy.last_to_proxy = 0;
00231 cpl_proxy_to_loc_set(intr->msg,&loc,intr->flags );
00232 break;
00233 default:
00234 LM_CRIT("unexpected ordering found "
00235 "when continuing proxying (%d)\n",intr->proxy.ordering);
00236 goto exit;
00237 }
00238
00239 return;
00240 } else {
00241
00242 LM_DBG("final_reply: got a final %d\n",ps->code);
00243 intr->ip = 0;
00244 if (ps->code==486 || ps->code==600) {
00245
00246 intr->ip = intr->proxy.busy;
00247 } else if (ps->code==408) {
00248
00249 intr->ip = intr->proxy.noanswer;
00250 } else if (((ps->code)/100)==3) {
00251
00252
00253 add_contacts_to_loc_set( ps->rpl, &(intr->loc_set));
00254 print_location_set( intr->loc_set );
00255 intr->ip = intr->proxy.redirect;
00256 } else {
00257
00258 intr->ip = intr->proxy.failure;
00259 }
00260
00261 if (intr->ip==0)
00262 intr->ip = (intr->proxy.default_)?
00263 intr->proxy.default_:DEFAULT_ACTION;
00264 if (intr->ip!=DEFAULT_ACTION)
00265 intr->ip = get_first_child( intr->ip );
00266
00267 if( intr->ip==DEFAULT_ACTION)
00268 rez = run_default(intr);
00269 else
00270 rez = cpl_run_script(intr);
00271 switch ( rez ) {
00272 case SCRIPT_END:
00273
00274
00275 case SCRIPT_TO_BE_CONTINUED:
00276 return;
00277 case SCRIPT_RUN_ERROR:
00278 case SCRIPT_FORMAT_ERROR:
00279 goto exit;
00280 default:
00281 LM_CRIT("improper result %d\n",
00282 rez);
00283 goto exit;
00284 }
00285 }
00286
00287 exit:
00288
00289
00290 free_cpl_interpreter( intr );
00291
00292 *(ps->param) = 0;
00293 return;
00294 }
00295
00296
00297
00298 static inline char *run_proxy( struct cpl_interpreter *intr )
00299 {
00300 unsigned short attr_name;
00301 unsigned short n;
00302 int_str is_val;
00303 char *kid;
00304 char *p;
00305 int i;
00306 str *s;
00307 struct location *loc;
00308
00309 intr->proxy.ordering = PARALLEL_VAL;
00310 intr->proxy.recurse = (unsigned short)cpl_env.proxy_recurse;
00311
00312
00313 for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
00314 get_basic_attr( p, attr_name, n, intr, script_error);
00315 switch (attr_name) {
00316 case TIMEOUT_ATTR:
00317 if (cpl_env.timer_avp.n || cpl_env.timer_avp.s.s) {
00318 is_val.n = n;
00319 if ( add_avp( cpl_env.timer_avp_type,
00320 cpl_env.timer_avp, is_val)<0) {
00321 LM_ERR("unable to set timer AVP\n");
00322
00323 }
00324 }
00325 break;
00326 case RECURSE_ATTR:
00327 switch (n) {
00328 case NO_VAL:
00329 intr->proxy.recurse = 0;
00330 break;
00331 case YES_VAL:
00332
00333 break;
00334 default:
00335 LM_ERR("invalid value (%u) found"
00336 " for attr. RECURSE in PROXY node!\n",n);
00337 goto script_error;
00338 }
00339 break;
00340 case ORDERING_ATTR:
00341 if (n!=PARALLEL_VAL && n!=SEQUENTIAL_VAL && n!=FIRSTONLY_VAL){
00342 LM_ERR("invalid value (%u) found"
00343 " for attr. ORDERING in PROXY node!\n",n);
00344 goto script_error;
00345 }
00346 intr->proxy.ordering = n;
00347 break;
00348 default:
00349 LM_ERR("unknown attribute (%d) in"
00350 "PROXY node\n",attr_name);
00351 goto script_error;
00352 }
00353 }
00354
00355 intr->proxy.busy = intr->proxy.noanswer = 0;
00356 intr->proxy.redirect = intr->proxy.failure = intr->proxy.default_ = 0;
00357
00358
00359
00360 for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
00361 kid = intr->ip + KID_OFFSET(intr->ip,i);
00362 check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
00363 switch ( NODE_TYPE(kid) ) {
00364 case BUSY_NODE :
00365 intr->proxy.busy = kid;
00366 break;
00367 case NOANSWER_NODE:
00368 intr->proxy.noanswer = kid;
00369 break;
00370 case REDIRECTION_NODE:
00371 intr->proxy.redirect = kid;
00372 break;
00373 case FAILURE_NODE:
00374 intr->proxy.failure = kid;
00375 break;
00376 case DEFAULT_NODE:
00377 intr->proxy.default_ = kid;
00378 break;
00379 default:
00380 LM_ERR("unknown output node type"
00381 " (%d) for PROXY node\n",NODE_TYPE(kid));
00382 goto script_error;
00383 }
00384 }
00385
00386
00387 if (intr->loc_set==0) {
00388 LM_DBG("location set found empty -> going on "
00389 "failure/default branch\n");
00390 if (intr->proxy.failure)
00391 return get_first_child(intr->proxy.failure);
00392 else if (intr->proxy.default_)
00393 return get_first_child(intr->proxy.default_);
00394 else return DEFAULT_ACTION;
00395 }
00396
00397
00398
00399 if (!(intr->flags&CPL_PROXY_DONE)) {
00400
00401
00402 s = GET_RURI( intr->msg );
00403 duplicate_str( s , intr->ruri );
00404 intr->flags |= CPL_RURI_DUPLICATED;
00405
00406 if (!intr->to) {
00407 if (!intr->msg->to &&
00408 (parse_headers(intr->msg,HDR_TO_F,0)==-1 || !intr->msg->to)) {
00409 LM_ERR("bad msg or missing TO header\n");
00410 goto runtime_error;
00411 }
00412 s = &(get_to(intr->msg)->uri);
00413 } else {
00414 s = intr->to;
00415 }
00416 duplicate_str( s , intr->to );
00417 intr->flags |= CPL_TO_DUPLICATED;
00418
00419 if (!intr->from) {
00420 if (parse_from_header( intr->msg )<0)
00421 goto runtime_error;
00422 s = &(get_from(intr->msg)->uri);
00423 } else {
00424 s = intr->from;
00425 }
00426 duplicate_str( s , intr->from );
00427 intr->flags |= CPL_FROM_DUPLICATED;
00428
00429 if (intr->subject!=STR_NOT_FOUND) {
00430 search_and_duplicate_hdr(intr,subject,HDR_SUBJECT_F,s);
00431 if (intr->subject!=STR_NOT_FOUND)
00432 intr->flags |= CPL_SUBJECT_DUPLICATED;
00433 }
00434
00435 if ( intr->organization!=STR_NOT_FOUND) {
00436 search_and_duplicate_hdr(intr,organization,HDR_ORGANIZATION_F,s);
00437 if ( intr->organization!=STR_NOT_FOUND)
00438 intr->flags |= CPL_ORGANIZATION_DUPLICATED;
00439 }
00440
00441 if (intr->user_agent!=STR_NOT_FOUND) {
00442 search_and_duplicate_hdr(intr,user_agent,HDR_USERAGENT_F,s);
00443 if (intr->user_agent!=STR_NOT_FOUND)
00444 intr->flags |= CPL_USERAGENT_DUPLICATED;
00445 }
00446
00447
00448 if (intr->accept_language!=STR_NOT_FOUND) {
00449 search_and_duplicate_hdr(intr,accept_language,
00450 HDR_ACCEPTLANGUAGE_F,s);
00451 if (intr->accept_language!=STR_NOT_FOUND)
00452 intr->flags |= CPL_ACCEPTLANG_DUPLICATED;
00453 }
00454
00455 if (intr->priority!=STR_NOT_FOUND) {
00456 search_and_duplicate_hdr(intr,priority,HDR_PRIORITY_F,s);
00457 if (intr->priority!=STR_NOT_FOUND)
00458 intr->flags |= CPL_PRIORITY_DUPLICATED;
00459 }
00460
00461
00462
00463
00464 if ( !(intr->flags&CPL_IS_STATEFUL) ) {
00465 i = cpl_fct.tmb.t_newtran( intr->msg );
00466 if (i<0) {
00467 LM_ERR("failed to build new transaction!\n");
00468 goto runtime_error;
00469 } else if (i==0) {
00470 LM_ERR("processed INVITE is a retransmission!\n");
00471
00472
00473 return EO_SCRIPT;
00474 }
00475 intr->flags |= CPL_IS_STATEFUL;
00476 }
00477
00478
00479
00480 if (cpl_fct.tmb.register_tmcb(intr->msg,0,
00481 TMCB_ON_FAILURE|TMCB_RESPONSE_OUT,reply_callback,(void*)intr,0) <= 0 ) {
00482 LM_ERR("failed to register TMCB_RESPONSE_OUT callback\n");
00483 goto runtime_error;
00484 }
00485 }
00486
00487 switch (intr->proxy.ordering) {
00488 case FIRSTONLY_VAL:
00489
00490
00491 loc = remove_first_location( &(intr->loc_set) );
00492 intr->proxy.last_to_proxy = 0;
00493
00494 intr->ip = CPL_TO_CONTINUE;
00495 if (cpl_proxy_to_loc_set(intr->msg,&loc,intr->flags )==-1)
00496 goto runtime_error;
00497 break;
00498 case PARALLEL_VAL:
00499
00500 intr->proxy.last_to_proxy = 0;
00501
00502 intr->ip = CPL_TO_CONTINUE;
00503 if (cpl_proxy_to_loc_set(intr->msg,&(intr->loc_set),intr->flags)
00504 ==-1)
00505 goto runtime_error;
00506 break;
00507 case SEQUENTIAL_VAL:
00508
00509
00510
00511 loc = remove_first_location( &(intr->loc_set) );
00512
00513 intr->proxy.last_to_proxy = intr->loc_set;
00514 while (intr->proxy.last_to_proxy&&intr->proxy.last_to_proxy->next)
00515 intr->proxy.last_to_proxy = intr->proxy.last_to_proxy->next;
00516
00517 intr->ip = CPL_TO_CONTINUE;
00518 if (cpl_proxy_to_loc_set(intr->msg,&loc,intr->flags)==-1)
00519 goto runtime_error;
00520 break;
00521 }
00522
00523 return CPL_TO_CONTINUE;
00524 script_error:
00525 return CPL_SCRIPT_ERROR;
00526 mem_error:
00527 LM_ERR("no more free shm memory\n");
00528 runtime_error:
00529 return CPL_RUNTIME_ERROR;
00530 }