t_reply.c
来自「性能优秀的SIP Proxy」· C语言 代码 · 共 1,744 行 · 第 1/4 页
C
1,744 行
p_msg, &len, &bm); return _reply_light(trans,buf,len,code,text, 0, 0, /* no to-tag */lock, &bm); }}/*if msg is set -> it will fake the env. vars conforming with the msg; if NULL * the env. will be restore to original */static inline void faked_env( struct cell *t,struct sip_msg *msg){ static struct cell *backup_t; static unsigned int backup_msgid; static struct usr_avp **backup_list; static struct socket_info* backup_si; static int backup_route_type; if (msg) { swap_route_type( backup_route_type, FAILURE_ROUTE); /* tm actions look in beginning whether transaction is * set -- whether we are called from a reply-processing * or a timer process, we need to set current transaction; * otherwise the actions would attempt to look the transaction * up (unnecessary overhead, refcounting) */ /* backup */ backup_t = get_t(); backup_msgid = global_msg_id; /* fake transaction and message id */ global_msg_id = msg->id; set_t(t); /* make available the avp list from transaction */ backup_list = set_avp_list( &t->user_avps ); /* set default send address to the saved value */ backup_si = bind_address; bind_address = t->uac[0].request.dst.send_sock; } else { /* restore original environment */ set_t(backup_t); global_msg_id = backup_msgid; set_route_type( backup_route_type ); /* restore original avp list */ set_avp_list( backup_list ); bind_address = backup_si; }}static inline int fake_req(struct sip_msg *faked_req, struct sip_msg *shm_msg, struct ua_server *uas, struct ua_client *uac){ /* on_negative_reply faked msg now copied from shmem msg (as opposed * to zero-ing) -- more "read-only" actions (exec in particular) will * work from reply_route as they will see msg->from, etc.; caution, * rw actions may append some pkg stuff to msg, which will possibly be * never released (shmem is released in a single block) */ memcpy( faked_req, shm_msg, sizeof(struct sip_msg)); /* if we set msg_id to something different from current's message * id, the first t_fork will properly clean new branch URIs */ faked_req->id=shm_msg->id-1; /* msg->parsed_uri_ok must be reset since msg_parsed_uri is * not cloned (and cannot be cloned) */ faked_req->parsed_uri_ok = 0; /* new_uri can change -- make a private copy */ faked_req->new_uri.s=pkg_malloc( uac->uri.len+1 ); if (!faked_req->new_uri.s) { LOG(L_ERR, "ERROR:tm:fake_req: no uri/pkg mem\n"); goto error; } faked_req->new_uri.len = uac->uri.len; memcpy( faked_req->new_uri.s, uac->uri.s, uac->uri.len); faked_req->new_uri.s[faked_req->new_uri.len]=0; /* dst_set is imposible to restore (since it's not saved), * so let it set to NULL */ /* set as flags the global flags and the flags from the elected branch */ faked_req->flags = uas->request->flags | uac->br_flags; return 1;error: return 0;}void inline static free_faked_req(struct sip_msg *faked_req, struct cell *t){ struct hdr_field *hdr; if (faked_req->new_uri.s) { pkg_free(faked_req->new_uri.s); faked_req->new_uri.s = 0; } /* free all types of lump that were added in failure handlers */ del_notflaged_lumps( &(faked_req->add_rm), LUMPFLAG_SHMEM ); del_notflaged_lumps( &(faked_req->body_lumps), LUMPFLAG_SHMEM ); del_nonshm_lump_rpl( &(faked_req->reply_lump) ); /* free header's parsed structures that were added by failure handlers */ for( hdr=faked_req->headers ; hdr ; hdr=hdr->next ) { if ( hdr->parsed && hdr_allocs_parse(hdr) && (hdr->parsed<(void*)t->uas.request || hdr->parsed>=(void*)t->uas.end_request)) { /* header parsed filed doesn't point inside uas.request memory * chunck -> it was added by failure funcs.-> free it as pkg */ DBG("DBG:free_faked_req: removing hdr->parsed %d\n", hdr->type); clean_hdr_field(hdr); hdr->parsed = 0; } }}/* return 1 if a failure_route processes */static inline int run_failure_handlers(struct cell *t){ static struct sip_msg faked_req; struct sip_msg *shmem_msg; struct ua_client *uac; int on_failure; shmem_msg = t->uas.request; uac = &t->uac[picked_branch]; /* failure_route for a local UAC? */ if (!shmem_msg || REQ_LINE(shmem_msg).method_value==METHOD_CANCEL ) { LOG(L_WARN,"WARNING:tm:run_failure_handlers: no UAC or CANCEL " "support (%d, %d) \n", t->on_negative, t->tmcb_hl.reg_types); return 0; } /* don't start faking anything if we don't have to */ if ( !has_tran_tmcbs( t, TMCB_ON_FAILURE) && !t->on_negative ) { LOG(L_WARN, "Warning: run_failure_handlers: no negative handler (%d, %d)\n", t->on_negative, t->tmcb_hl.reg_types); return 1; } if (!fake_req(&faked_req, shmem_msg, &t->uas, uac)) { LOG(L_ERR, "ERROR: run_failure_handlers: fake_req failed\n"); return 0; } /* fake also the env. conforming to the fake msg */ faked_env( t, &faked_req); /* DONE with faking ;-) -> run the failure handlers */ if ( has_tran_tmcbs( t, TMCB_ON_FAILURE) ) { run_trans_callbacks( TMCB_ON_FAILURE, t, &faked_req, uac->reply, uac->last_received); } if (t->on_negative) { /* avoid recursion -- if failure_route forwards, and does not * set next failure route, failure_route will not be reentered * on failure */ on_failure = t->on_negative; t->on_negative=0; /* run a reply_route action if some was marked */ run_top_route(failure_rlist[on_failure], &faked_req); } /* restore original environment and free the fake msg */ faked_env( t, 0); free_faked_req(&faked_req,t); /* if failure handler changed flag, update transaction context */ shmem_msg->flags = faked_req.flags & gflags_mask; return 1;}/* select a branch for forwarding; returns: * 0..X ... branch number * -1 ... error * -2 ... can't decide yet -- incomplete branches present */static inline int t_pick_branch( struct cell *t, int *res_code){ int lowest_b, lowest_s, b; int cancelled; lowest_b=-1; lowest_s=999; cancelled = (t->flags&T_WAS_CANCELLED_FLAG); for ( b=t->first_branch; b<t->nr_of_outgoings ; b++ ) { /* skip 'empty branches' */ if (!t->uac[b].request.buffer.s) continue; /* there is still an unfinished UAC transaction; wait now! */ if ( t->uac[b].last_received<200 ) return -2; /* replyes to cancel has max priority */ if ( (cancelled && t->uac[b].last_received==487) || (t->uac[b].last_received<lowest_s && (lowest_s!=487 || !cancelled))) { lowest_b =b; lowest_s = t->uac[b].last_received; } } /* find lowest branch */ DBG("DEBUG:tm:t_pick_branch: picked branch %d, code %d\n", lowest_b,lowest_s); *res_code=lowest_s; return lowest_b;}/* This is the neurological point of reply processing -- called * from within a REPLY_LOCK, t_should_relay_response decides * how a reply shall be processed and how transaction state is * affected. * * Checks if the new reply (with new_code status) should be sent or not * based on the current * transaction status. * Returns - branch number (0,1,...) which should be relayed * -1 if nothing to be relayed */static enum rps t_should_relay_response( struct cell *Trans , int new_code, int branch , int *should_store, int *should_relay, branch_bm_t *cancel_bitmap, struct sip_msg *reply ){ int branch_cnt; int picked_code; int inv_through; /* note: this code never lets replies to CANCEL go through; we generate always a local 200 for CANCEL; 200s are not relayed because it's not an INVITE transaction; >= 300 are not relayed because 200 was already sent out */ DBG("DEBUG:tm:t_should_relay_response: T_code=%d, new_code=%d\n", Trans->uas.status,new_code); inv_through=new_code>=200 && new_code<300 && is_invite(Trans); /* if final response sent out, allow only INVITE 2xx */ if ( Trans->uas.status >= 200 ) { if (inv_through) { DBG("DEBUG:tm:t_should_relay_response: 200 OK for INVITE " "after final sent\n"); *should_store=0; Trans->uac[branch].last_received=new_code; *should_relay=branch; return RPS_PUSHED_AFTER_COMPLETION; } if ( is_hopbyhop_cancel(Trans) && new_code>=200) { *should_store=0; *should_relay=-1; picked_branch=-1; return RPS_COMPLETED; } /* except the exception above, too late messages will be discarded */ goto discard; } /* if final response received at this branch, allow only INVITE 2xx */ if (Trans->uac[branch].last_received>=200 && !(inv_through && Trans->uac[branch].last_received<300)) {#ifdef EXTRA_DEBUG /* don't report on retransmissions */ if (Trans->uac[branch].last_received==new_code) { DBG("DEBUG:tm:t_should_relay_response: final reply " "retransmission\n"); } else /* if you FR-timed-out, faked a local 408 and 487 came, don't * report on it either */ if (Trans->uac[branch].last_received==408 && new_code==487) { DBG("DEBUG:tm:t_should_relay_response: 487 reply came for a " "timed-out branch\n"); } else { /* this looks however how a very strange status rewrite attempt; * report on it */ DBG("DEBUG:tm:t_should_relay_response: status rewrite by UAS: " "stored: %d, received: %d\n", Trans->uac[branch].last_received, new_code ); }#endif goto discard; } /* no final response sent yet */ /* negative replies subject to fork picking */ if (new_code >=300 ) { Trans->uac[branch].last_received=new_code; /* also append the current reply to the transaction to * make it available in failure routes - a kind of "fake" * save of the final reply per branch */ Trans->uac[branch].reply = reply; /* if all_final return lowest */ picked_branch = t_pick_branch( Trans, &picked_code); if (picked_branch==-2) { /* branches open yet */ *should_store=1; *should_relay=-1; picked_branch=-1; return RPS_STORE; } if (picked_branch==-1) { LOG(L_CRIT, "ERROR:tm:t_should_relay_response: pick_branch failed " "(lowest==-1) for code %d\n",new_code); goto discard; } /* no more pending branches -- try if that changes after * a callback; save branch count to be able to determine * later if new branches were initiated */ branch_cnt=Trans->nr_of_outgoings; /* run ON_FAILURE handlers ( route and callbacks) */ if ( has_tran_tmcbs( Trans, TMCB_ON_FAILURE) || Trans->on_negative ) { run_failure_handlers( Trans ); } /* now reset it; after the failure logic, the reply may * not be stored any more and we don't want to keep into * transaction some broken reference */ Trans->uac[branch].reply = 0; /* look if the callback perhaps replied transaction; it also covers the case in which a transaction is replied localy on CANCEL -- then it would make no sense to proceed to new branches bellow */ if (Trans->uas.status >= 200) { *should_store=0; *should_relay=-1; /* this might deserve an improvement -- if something was already replied, it was put on wait and then, returning RPS_COMPLETED will make t_on_reply put it on wait again; perhaps splitting put_on_wait from send_reply or a new RPS_ code would be healthy */ picked_branch=-1; return RPS_COMPLETED; } /* look if the callback/failure_route introduced new branches ... */ if (branch_cnt<Trans->nr_of_outgoings) { /* await then result of new branches */ *should_store=1; *should_relay=-1; picked_branch=-1; return RPS_STORE; } /* really no more pending branches -- return selected code */ *should_store=0; *should_relay=picked_branch; picked_branch=-1; return RPS_COMPLETED; } /* not >=300 ... it must be 2xx or provisional 1xx */ if (new_code>=100) { /* 1xx and 2xx except 100 will be relayed */ Trans->uac[branch].last_received=new_code; *should_store=0; *should_relay= new_code==100? -1 : branch; if (new_code>=200 ) { which_cancel( Trans, cancel_bitmap ); return RPS_COMPLETED; } else return RPS_PROVISIONAL; }discard: *should_store=0; *should_relay=-1; return RPS_DISCARDED;}/* Retransmits the last sent inbound reply. * input: p_msg==request for which I want to retransmit an associated reply * Returns -1 - error * 1 - OK */int t_retransmit_reply( struct cell *t ){ static char b[BUF_SIZE]; int len; /* we need to lock the transaction as messages from upstream may change it continuously */ LOCK_REPLIES( t ); if (!t->uas.response.buffer.s) { DBG("DEBUG:tm:t_retransmit_reply: nothing to retransmit\n"); goto error; } /* response.dst.send_sock should be valid all the time now, as it's taken from original request -bogdan */ if (t->uas.response.dst.send_sock==0) { LOG(L_CRIT,"BUG:tm:t_retransmit_reply: something to retransmit, but" "send_sock is NULL\n"); goto error; } len=t->uas.response.buffer.len; if ( len==0 || len>BUF_SIZE ) { DBG("DEBUG:tm:t_retransmit_reply: zero length or too big " "to retransmit: %d\n", len); goto error; } memcpy( b, t->uas.response.buffer.s, len ); UNLOCK_REPLIES( t ); SEND_PR_BUFFER( & t->uas.response, b, len ); DBG("DEBUG:tm:t_retransmit_reply: buf=%p: %.9s..., shmem=%p: %.9s\n", b, b, t->uas.response.buffer.s, t->uas.response.buffer.s ); return 1;error: UNLOCK_REPLIES(t); return -1;}int t_reply( struct cell *t, struct sip_msg* p_msg, unsigned int code, char * text ){ return _reply( t, p_msg, code, text, 1 /* lock replies */ );}int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code, char * text ){ return _reply( t, p_msg, code, text, 0 /* don't lock replies */ );}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?