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