📄 t_reply.c
字号:
memcpy( b, t->uas.response.buffer, len ); UNLOCK_REPLIES( t ); SEND_PR_BUFFER( & t->uas.response, b, len ); DBG("DEBUG: reply retransmitted. buf=%p: %.9s..., shmem=%p: %.9s\n", b, b, t->uas.response.buffer, t->uas.response.buffer ); 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 */ );}void set_final_timer( /* struct s_table *h_table, */ struct cell *t ){ if ( !is_local(t) && t->uas.request->REQ_METHOD==METHOD_INVITE ) { /* crank timers for negative replies */ if (t->uas.status>=300) { start_retr(&t->uas.response); return; } /* local UAS retransmits too */ if (t->relaied_reply_branch==-2 && t->uas.status>=200) { /* we retransmit 200/INVs regardless of transport -- even if TCP used, UDP could be used upstream and loose the 200, which is not retransmitted by proxies */ force_retr( &t->uas.response ); return; } } put_on_wait(t);}void cleanup_uac_timers( struct cell *t ){ int i; /* reset FR/retransmission timers */ for (i=0; i<t->nr_of_outgoings; i++ ) { reset_timer( &t->uac[i].request.retr_timer ); reset_timer( &t->uac[i].request.fr_timer ); } DBG("DEBUG: cleanup_uac_timers: RETR/FR timers reset\n");}static int store_reply( struct cell *trans, int branch, struct sip_msg *rpl){# ifdef EXTRA_DEBUG if (trans->uac[branch].reply) { LOG(L_ERR, "ERROR: replacing stored reply; aborting\n"); abort(); }# endif /* when we later do things such as challenge aggregation, we should parse the message here before we conserve it in shared memory; -jiri */ if (rpl==FAKED_REPLY) trans->uac[branch].reply=FAKED_REPLY; else trans->uac[branch].reply = sip_msg_cloner( rpl, 0 ); if (! trans->uac[branch].reply ) { LOG(L_ERR, "ERROR: store_reply: can't alloc' clone memory\n"); return 0; } return 1;}/* this is the code which decides what and when shall be relayed upstream; note well -- it assumes it is entered locked with REPLY_LOCK and it returns unlocked!*/enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, unsigned int msg_status, branch_bm_t *cancel_bitmap ){ int relay; int save_clone; char *buf; /* length of outbound reply */ unsigned int res_len; int relayed_code; struct sip_msg *relayed_msg; struct bookmark bm; int totag_retr; enum rps reply_status; /* retransmission structure of outbound reply and request */ struct retr_buf *uas_rb; /* keep compiler warnings about use of uninit vars silent */ res_len=0; buf=0; relayed_msg=0; relayed_code=0; totag_retr=0; /* remember, what was sent upstream to know whether we are * forwarding a first final reply or not */ /* *** store and relay message as needed *** */ reply_status = t_should_relay_response(t, msg_status, branch, &save_clone, &relay, cancel_bitmap, p_msg ); DBG("DEBUG: relay_reply: branch=%d, save=%d, relay=%d\n", branch, save_clone, relay ); /* store the message if needed */ if (save_clone) /* save for later use, typically branch picking */ { if (!store_reply( t, branch, p_msg )) goto error01; } uas_rb = & t->uas.response; if (relay >= 0 ) { /* initialize sockets for outbound reply */ uas_rb->activ_type=msg_status; /* only messages known to be relayed immediately will be * be called on; we do not evoke this callback on messages * stored in shmem -- they are fixed and one cannot change them * anyway */ if (msg_status<300 && branch==relay && has_tran_tmcbs(t,TMCB_RESPONSE_FWDED) ) { run_trans_callbacks( TMCB_RESPONSE_FWDED, t, t->uas.request, p_msg, msg_status ); } /* try building the outbound reply from either the current * or a stored message */ relayed_msg = branch==relay ? p_msg : t->uac[relay].reply; if (relayed_msg==FAKED_REPLY) { tm_stats->replied_localy++; relayed_code = branch==relay ? msg_status : t->uac[relay].last_received; if (relayed_code>=180 && t->uas.request->to && (get_to(t->uas.request)->tag_value.s==0 || get_to(t->uas.request)->tag_value.len==0)) { calc_crc_suffix( t->uas.request, tm_tag_suffix ); buf = build_res_buf_from_sip_req( relayed_code, error_text(relayed_code), &tm_tag, t->uas.request, &res_len, &bm ); } else { buf = build_res_buf_from_sip_req( relayed_code, error_text(relayed_code), 0/* no to-tag */, t->uas.request, &res_len, &bm ); } } else { relayed_code=relayed_msg->REPLY_STATUS; buf = build_res_buf_from_sip_res( relayed_msg, &res_len ); /* if we build a message from shmem, we need to remove via delete lumps which are now stirred in the shmem-ed structure */ if (branch!=relay) { free_via_clen_lump(&relayed_msg->add_rm); } } update_reply_stats( relayed_code ); if (!buf) { LOG(L_ERR, "ERROR: relay_reply: " "no mem for outbound reply buffer\n"); goto error02; } /* attempt to copy the message to UAS's shmem: - copy to-tag for ACK matching as well - allocate little a bit more for provisional as larger messages are likely to follow and we will be able to reuse the memory frag */ uas_rb->buffer = (char*)shm_resize( uas_rb->buffer, res_len + (msg_status<200 ? REPLY_OVERBUFFER_LEN : 0)); if (!uas_rb->buffer) { LOG(L_ERR, "ERROR: relay_reply: cannot alloc reply shmem\n"); goto error03; } uas_rb->buffer_len = res_len; memcpy( uas_rb->buffer, buf, res_len ); if (relayed_msg==FAKED_REPLY) { /* to-tags for local replies */ update_local_tags(t, &bm, uas_rb->buffer, buf); } tm_stats->replied_localy++; /* update the status ... */ t->uas.status = relayed_code; t->relaied_reply_branch = relay; if (is_invite(t) && relayed_msg!=FAKED_REPLY && relayed_code>=200 && relayed_code < 300 && has_tran_tmcbs( t, TMCB_RESPONSE_OUT|TMCB_E2EACK_IN) ) { totag_retr=update_totag_set(t, relayed_msg); } }; /* if relay ... */ UNLOCK_REPLIES( t ); /* Setup retransmission timer _before_ the reply is sent * to avoid race conditions */ if (reply_status == RPS_COMPLETED) { set_final_timer(t); } /* send it now (from the private buffer) */ if (relay >= 0) { SEND_PR_BUFFER( uas_rb, buf, res_len ); DBG("DEBUG: reply relayed. buf=%p: %.9s..., shmem=%p: %.9s\n", buf, buf, uas_rb->buffer, uas_rb->buffer ); if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) { run_trans_callbacks( TMCB_RESPONSE_OUT, t, t->uas.request, relayed_msg, relayed_code); } pkg_free( buf ); } /* success */ return reply_status;error03: pkg_free( buf );error02: if (save_clone) { if (t->uac[branch].reply!=FAKED_REPLY) sip_msg_free( t->uac[branch].reply ); t->uac[branch].reply = NULL; }error01: t_reply_unsafe( t, t->uas.request, 500, "Reply processing error" ); UNLOCK_REPLIES(t); if (is_invite(t)) cancel_uacs( t, *cancel_bitmap ); /* a serious error occurred -- attempt to send an error reply; it will take care of clean-ups */ /* failure */ return RPS_ERROR;}/* this is the "UAC" above transaction layer; if a final reply is received, it triggers a callback; note well -- it assumes it is entered locked with REPLY_LOCK and it returns unlocked!*/enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch, unsigned int msg_status, branch_bm_t *cancel_bitmap){ /* how to deal with replies for local transaction */ int local_store, local_winner; enum rps reply_status; struct sip_msg *winning_msg; int winning_code; int totag_retr; /* branch_bm_t cancel_bitmap; */ /* keep warning 'var might be used un-inited' silent */ winning_msg=0; winning_code=0; totag_retr=0; *cancel_bitmap=0; reply_status=t_should_relay_response( t, msg_status, branch, &local_store, &local_winner, cancel_bitmap, p_msg ); DBG("DEBUG: local_reply: branch=%d, save=%d, winner=%d\n", branch, local_store, local_winner ); if (local_store) { if (!store_reply(t, branch, p_msg)) goto error; } if (local_winner>=0) { winning_msg= branch==local_winner ? p_msg : t->uac[local_winner].reply; if (winning_msg==FAKED_REPLY) { tm_stats->replied_localy++; winning_code = branch==local_winner ? msg_status : t->uac[local_winner].last_received; } else { winning_code=winning_msg->REPLY_STATUS; } t->uas.status = winning_code; update_reply_stats( winning_code ); if (is_invite(t) && winning_msg!=FAKED_REPLY && winning_code>=200 && winning_code <300 && has_tran_tmcbs(t,TMCB_RESPONSE_OUT|TMCB_E2EACK_IN) ) { totag_retr=update_totag_set(t, winning_msg); } } UNLOCK_REPLIES(t); if (local_winner>=0 && winning_code>=200 ) { DBG("DEBUG: local transaction completed\n"); if (!totag_retr) { if ( has_tran_tmcbs(t,TMCB_LOCAL_COMPLETED) ) run_trans_callbacks( TMCB_LOCAL_COMPLETED, t, 0, winning_msg, winning_code ); } } return reply_status;error: which_cancel(t, cancel_bitmap); UNLOCK_REPLIES(t); cleanup_uac_timers(t); if ( get_cseq(p_msg)->method.len==INVITE_LEN && memcmp( get_cseq(p_msg)->method.s, INVITE, INVITE_LEN)==0) cancel_uacs( t, *cancel_bitmap ); put_on_wait(t); return RPS_ERROR;}/* This function is called whenever a reply for our module is received; * we need to register this function on module initialization; * Returns : 0 - core router stops * 1 - core router relay statelessly */int reply_received( struct sip_msg *p_msg ){ int msg_status, last_uac_status, branch, reply_status; char *ack; unsigned int ack_len, timer; /* has the transaction completed now and we need to clean-up? */ branch_bm_t cancel_bitmap; struct ua_client *uac; struct cell *t; str next_hop; struct usr_avp **backup_list; /* make sure we know the associated transaction ... */ if (t_check(p_msg, &branch ) == -1) return 1; /*... if there is none, tell the core router to fwd statelessly */ t = get_t(); if ((t == 0) || (t == T_UNDEFINED)) return 1; cancel_bitmap=0; msg_status=p_msg->REPLY_STATUS; uac=&t->uac[branch]; DBG("DEBUG: reply_received: org. status uas=%d, " "uac[%d]=%d local=%d is_invite=%d)\n", t->uas.status, branch, uac->last_received, is_local(t), is_invite(t)); last_uac_status=uac->last_received; /* it's a cancel ... ? */ if (get_cseq(p_msg)->method.len == CANCEL_LEN && memcmp( get_cseq(p_msg)->method.s, CANCEL, CANCEL_LEN) == 0 /* .. which is not e2e ? ... */ && is_invite(t) ) { /* ... then just stop timers */ reset_timer( &uac->local_cancel.retr_timer); if ( msg_status >= 200 ) { reset_timer( &uac->local_cancel.fr_timer); } DBG("DEBUG: reply to local CANCEL processed\n"); goto done; } /* *** stop timers *** */ /* stop retransmission */ reset_timer(&uac->request.retr_timer); /* stop final response timer only if I got a final response */ if ( msg_status >= 200 ) { reset_timer( &uac->request.fr_timer); } /* acknowledge negative INVITE replies (do it before detailed * on_reply processing, which may take very long, like if it * is attempted to establish a TCP connection to a fail-over dst */ if (is_invite(t)) { if (msg_status >= 300) { ack = build_ack(p_msg, t, branch, &ack_len); if (ack) { SEND_PR_BUFFER(&uac->request, ack, ack_len); shm_free(ack); } } else if (is_local(t) && msg_status >= 200) { ack = build_local_ack(p_msg, t, branch, &ack_len, &next_hop); if (ack) { if (send_local_ack(p_msg, &next_hop, ack, ack_len) < 0) { LOG(L_ERR, "Error while sending local ACK\n"); } shm_free(ack); } } } /* processing of on_reply block */ if (t->on_reply) { rmode = MODE_ONREPLY; /* transfer transaction flag to message context */ if (t->uas.request) p_msg->flags = t->uas.request->flags; /* set the as avp_list the one from transaction */ backup_list = set_avp_list(&t->user_avps); if (run_actions(onreply_rlist[t->on_reply], p_msg)<0) { LOG(L_ERR, "ERROR: on_reply processing failed\n"); } /* transfer current message context back to t */ if (t->uas.request) t->uas.request->flags=p_msg->flags; /* restore original avp list */ set_avp_list( backup_list ); } LOCK_REPLIES( t ); if (is_local(t)) { reply_status = local_reply(t, p_msg, branch, msg_status, &cancel_bitmap); if (reply_status == RPS_COMPLETED) { cleanup_uac_timers(t); if (is_invite(t)) cancel_uacs(t, cancel_bitmap); /* There is no need to call set_final_timer because we know * that the transaction is local */ put_on_wait(t); } } else { reply_status = relay_reply(t, p_msg, branch, msg_status, &cancel_bitmap); /* clean-up the transaction when transaction completed */ if (reply_status == RPS_COMPLETED) { /* no more UAC FR/RETR (if I received a 2xx, there may * be still pending branches ... */ cleanup_uac_timers(t);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -