📄 t_fwd.c
字号:
error: return ret;}int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite, int branch ){ int ret; char *shbuf; unsigned int len; str bk_dst_uri; if (t_cancel->uac[branch].request.buffer.s) { LOG(L_CRIT, "ERROR: e2e_cancel_branch: buffer rewrite attempt\n"); ret=ser_error=E_BUG; goto error; } /* note -- there is a gap in proxy stats -- we don't update proxy stats with CANCEL (proxy->ok, proxy->tx, etc.) */ cancel_msg->new_uri = t_invite->uac[branch].uri; cancel_msg->parsed_uri_ok=0; bk_dst_uri = cancel_msg->dst_uri; if ( pre_print_uac_request( t_cancel, branch, cancel_msg)!= 0 ) { ret = -1; goto error01; } /* force same uri as in INVITE */ if (cancel_msg->new_uri.s!=t_invite->uac[branch].uri.s) { pkg_free(cancel_msg->new_uri.s); cancel_msg->new_uri = t_invite->uac[branch].uri; /* and just to be sure */ cancel_msg->parsed_uri_ok = 0; } /* print */ shbuf=print_uac_request( cancel_msg, &len, t_invite->uac[branch].request.dst.send_sock, t_invite->uac[branch].request.dst.proto); if (!shbuf) { LOG(L_ERR, "ERROR: e2e_cancel_branch: printing e2e cancel failed\n"); ret=ser_error=E_OUT_OF_MEM; goto error01; } /* install buffer */ t_cancel->uac[branch].request.dst=t_invite->uac[branch].request.dst; t_cancel->uac[branch].request.buffer.s=shbuf; t_cancel->uac[branch].request.buffer.len=len; t_cancel->uac[branch].uri.s=t_cancel->uac[branch].request.buffer.s+ cancel_msg->first_line.u.request.method.len+1; t_cancel->uac[branch].uri.len=t_invite->uac[branch].uri.len; t_cancel->uac[branch].br_flags = cancel_msg->flags&(~gflags_mask); /* success */ ret=1;error01: post_print_uac_request( cancel_msg, &t_invite->uac[branch].uri, &bk_dst_uri); cancel_msg->dst_uri = bk_dst_uri;error: return ret;}void e2e_cancel( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite ){ branch_bm_t cancel_bm; branch_bm_t dummy_bm; int i; int lowest_error; str backup_uri; int rurib_flags; int ret; cancel_bm=0; lowest_error=0; /* e2e_cancel_branch() makes no RURI parsing, so no need to * save the -> parse_uri_ok */ backup_uri = cancel_msg->new_uri; /* branch flags specific to RURI */ rurib_flags = cancel_msg->flags&(~gflags_mask); /* determine which branches to cancel ... */ which_cancel( t_invite, &cancel_bm ); t_cancel->nr_of_outgoings=t_invite->nr_of_outgoings; t_cancel->first_branch=t_invite->first_branch; /* fix label -- it must be same for reply matching */ t_cancel->label=t_invite->label; /* ... and install CANCEL UACs */ for (i=t_invite->first_branch; i<t_invite->nr_of_outgoings; i++) { if (cancel_bm & (1<<i)) { ret=e2e_cancel_branch(cancel_msg, t_cancel, t_invite, i); if (ret<0) cancel_bm &= ~(1<<i); if (ret<lowest_error) lowest_error=ret; } } /* restore new_uri */ cancel_msg->new_uri = backup_uri; cancel_msg->parsed_uri_ok = 0; /* set flags */ cancel_msg->flags = (cancel_msg->flags&gflags_mask)|rurib_flags; t_cancel->uas.request->flags = cancel_msg->flags&gflags_mask; /* send them out */ for (i=t_cancel->first_branch; i<t_cancel->nr_of_outgoings; i++) { if (cancel_bm & (1<<i)) { if ( has_tran_tmcbs( t_cancel, TMCB_REQUEST_BUILT) ) { set_extra_tmcb_params( &t_cancel->uac[i].request.buffer, &t_cancel->uac[i].request.dst); run_trans_callbacks( TMCB_REQUEST_BUILT, t_cancel, cancel_msg, 0, -cancel_msg->REQ_METHOD); } if (SEND_BUFFER( &t_cancel->uac[i].request)==-1) { LOG(L_ERR, "ERROR: e2e_cancel: send failed\n"); } start_retr( &t_cancel->uac[i].request ); } } /* internally cancel branches with no received reply */ for (i=t_invite->first_branch; i<t_invite->nr_of_outgoings; i++) { if (t_invite->uac[i].last_received==0){ /* mark as cancelled */ t_invite->uac[i].flags |= T_UAC_TO_CANCEL_FLAG; /* reset the "request" timers */ reset_timer(&t_invite->uac[i].request.retr_timer); reset_timer(&t_invite->uac[i].request.fr_timer); LOCK_REPLIES( t_invite ); if (RPS_ERROR==relay_reply(t_invite,FAKED_REPLY,i,487,&dummy_bm)) lowest_error = -1; /* force sending 500 error */ } } /* do not attmpt to send reply for CANCEL if we already did it once; * to work arround the race between receiveing reply and generating * local reply, we better check if we are in failure route (which means that * the reply to UAC is /to be/ sent) or if was actually sent out */ /* calling here t_relay from within failure route will lead to dead lock * on the transaction's reply lock -bogdan */ if (route_type==FAILURE_ROUTE || t_cancel->uas.status>=200) return; /* if error occurred, let it know upstream (final reply will also move the transaction on wait state */ if (lowest_error<0) { LOG(L_ERR, "ERROR: cancel error\n"); t_reply( t_cancel, cancel_msg, 500, "cancel error"); /* if there are pending branches, let upstream know we are working on it */ } else if (cancel_bm) { DBG("DEBUG: e2e_cancel: e2e cancel proceeding\n"); t_cancel->flags |= T_HOPBYHOP_CANCEL_FLAG; t_reply( t_cancel, cancel_msg, 200, CANCELING ); /* if the transaction exists, but there is no more pending branch, tell upstream we're done */ } else { DBG("DEBUG: e2e_cancel: e2e cancel -- no more pending branches\n"); t_reply( t_cancel, cancel_msg, 200, CANCEL_DONE ); }#ifdef LOCAL_487 /* local 487s have been deprecated -- it better handles * race conditions (UAS sending 200); hopefully there are * no longer UACs who go crazy waiting for the 487 whose * forwarding is being blocked by other unresponsive branch */ /* we could await downstream UAS's 487 replies; however, if some of the branches does not do that, we could wait long time and annoy upstream UAC which wants to see a result of CANCEL quickly */ DBG("DEBUG: e2e_cancel: sending 487\n"); /* in case that something in the meantime has been sent upstream (like if FR hit at the same time), don't try to send */ if (t_invite->uas.status>=200) return; /* there is still a race-condition -- the FR can hit now; that's not too bad -- we take care in t_reply's REPLY_LOCK; in the worst case, both this t_reply and other replier will try, and the later one will result in error message "can't reply twice" */ t_reply(t_invite, t_invite->uas.request, 487, CANCELED );#endif}/* function returns: * 1 - forward successful * -1 - error during forward */int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , struct proxy_l * proxy){ str backup_uri; str backup_dst; int branch_ret, lowest_ret; str current_uri; branch_bm_t added_branches; int i, q; struct cell *t_invite; int success_branch; int try_new; str dst_uri; struct socket_info *bk_sock; int rurib_flags; int br_flags; int idx; str path; /* make -Wall happy */ current_uri.s=0; if (p_msg->REQ_METHOD==METHOD_CANCEL) { t_invite=t_lookupOriginalT( p_msg ); if (t_invite!=T_NULL_CELL) { t_invite->flags |= T_WAS_CANCELLED_FLAG; e2e_cancel( p_msg, t, t_invite ); UNREF(t_invite); return 1; } } /* do not forward requests which were already cancelled*/ if (was_cancelled(t)) { LOG(L_ERR,"ERROR:tm:t_forward_nonack: discarding fwd for " "a cancelled transaction\n"); return -1; } /* backup current uri, sock and flags ... add_uac changes it */ backup_uri = p_msg->new_uri; backup_dst = p_msg->dst_uri; bk_sock = p_msg->force_send_socket; rurib_flags = p_msg->flags&(~gflags_mask); /* if no more specific error code is known, use this */ lowest_ret=E_BUG; /* branches added */ added_branches=0; /* branch to begin with */ t->first_branch=t->nr_of_outgoings; /* on first-time forwarding, use current uri, later only what is in additional branches (which may be continuously refilled) */ if (t->first_branch==0) { try_new=1; current_uri = *GET_RURI(p_msg); branch_ret = add_uac( t, p_msg, ¤t_uri, &backup_dst, &p_msg->path_vec, proxy); if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } else try_new=0; for( idx=0; (current_uri.s=get_branch( idx, ¤t_uri.len, &q, &dst_uri, &path, &br_flags, &p_msg->force_send_socket))!=0 ; idx++ ) { try_new++; p_msg->flags = (p_msg->flags&gflags_mask) | br_flags; branch_ret=add_uac( t, p_msg, ¤t_uri, &dst_uri, &path, proxy); /* pick some of the errors in case things go wrong; note that picking lowest error is just as good as any other algorithm which picks any other negative branch result */ if (branch_ret>=0) added_branches |= 1<<branch_ret; else lowest_ret=branch_ret; } /* consume processed branches */ clear_branches(); /* restore original stuff */ p_msg->new_uri=backup_uri; p_msg->parsed_uri_ok = 0;/* just to be sure; add_uac may parse other uris*/ p_msg->dst_uri = backup_dst; p_msg->force_send_socket = bk_sock; /* update on_branch, if modified */ t->on_branch = get_on_branch(); /* set flags */ p_msg->flags = (p_msg->flags&gflags_mask)|rurib_flags; t->uas.request->flags = p_msg->flags&gflags_mask; /* don't forget to clear all branches processed so far */ /* things went wrong ... no new branch has been fwd-ed at all */ if (added_branches==0) { if (try_new==0) { LOG(L_ERR, "ERROR:tm:t_forward_nonack: no branch for " "forwarding\n"); return -1; } LOG(L_ERR, "ERROR:tm:t_forward_nonack: failure to add branches\n"); return lowest_ret; } /* send them out now */ success_branch=0; for (i=t->first_branch; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { if ( has_tran_tmcbs( t, TMCB_REQUEST_BUILT) ) { set_extra_tmcb_params( &t->uac[i].request.buffer, &t->uac[i].request.dst); run_trans_callbacks( TMCB_REQUEST_BUILT, t, p_msg,0, -p_msg->REQ_METHOD); } if (SEND_BUFFER( &t->uac[i].request)==-1) { LOG(L_ERR, "ERROR:tm:t_forward_nonack: sending request " "failed\n"); if (proxy) { proxy->errors++; proxy->ok=0; } } else { success_branch++; } start_retr( &t->uac[i].request ); set_kr(REQ_FWDED); } } if (success_branch<=0) { ser_error=E_SEND; return -1; } return 1;}int t_replicate(struct sip_msg *p_msg, str *dst){ /* this is a quite horrible hack -- we just take the message as is, including Route-s, Record-route-s, and Vias , forward it downstream and prevent replies received from relaying by setting the replication/local_trans bit; nevertheless, it should be good enough for the primary customer of this function, REGISTER replication if we want later to make it thoroughly, we need to introduce delete lumps for all the header fields above */ if ( set_dst_uri( p_msg, dst)!=0 ) { LOG(L_ERR,"ERROR:tm:t_replicate: failed to set dst uri\n"); return -1; } if ( branch_uri2dset( GET_RURI(p_msg) )!=0 ) { LOG(L_ERR,"ERROR:tm:t_replicate: failed to convert uri to dst\n"); return -1; } return t_relay_to( p_msg, 0, 1/* replicate */);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -