void run_onsend_callbacks(int type, struct retr_buf* rbuf, struct sip_msg* req, struct sip_msg* repl, short flags) { struct tmcb_params params; struct cell * trans; trans=rbuf->my_T; if ( trans==0 || trans->tmcb_hl.first==0 || ((trans->tmcb_hl.reg_types)&type)==0 ) return; INIT_TMCB_ONSEND_PARAMS(params, req, repl, rbuf, &rbuf->dst, rbuf->buffer, rbuf->buffer_len, flags, rbuf->branch, rbuf->activ_type); /* req, rpl */ run_trans_callbacks_internal(&trans->tmcb_hl, type, trans, ¶ms); }
/** * @return: * 0: success * -1: internal error * -2: insane call :) */ int ack_local_uac(struct cell *trans, str *hdrs, str *body) { struct retr_buf *local_ack, *old_lack; int ret; struct tmcb_params onsend_params; /* sanity checks */ #ifdef EXTRA_DEBUG if (! trans) { BUG("no transaction to ACK.\n"); abort(); } #endif #define RET_INVALID \ ret = -2; \ goto fin if (! is_local(trans)) { ERR("trying to ACK non local transaction (T@%p).\n", trans); RET_INVALID; } if (! is_invite(trans)) { ERR("trying to ACK non INVITE local transaction (T@%p).\n", trans); RET_INVALID; } if (! trans->uac[0].reply) { ERR("trying to ACK un-completed INVITE transaction (T@%p).\n", trans); RET_INVALID; } if (! (trans->flags & T_NO_AUTO_ACK)) { ERR("trying to ACK an auto-ACK transaction (T@%p).\n", trans); RET_INVALID; } if (trans->uac[0].local_ack) { ERR("trying to rebuild ACK retransmission buffer (T@%p).\n", trans); RET_INVALID; } /* looks sane: build the retransmission buffer */ if (! (local_ack = local_ack_rb(trans->uac[0].reply, trans, /*branch*/0, hdrs, body))) { ERR("failed to build ACK retransmission buffer"); RET_INVALID; } else { /* set the new buffer, but only if not already set (conc. invok.) */ if ((old_lack = (struct retr_buf *)atomic_cmpxchg_long( (void *)&trans->uac[0].local_ack, 0, (long)local_ack))) { /* buffer already set: deny current attempt */ ERR("concurrent ACKing for local INVITE detected (T@%p).\n",trans); free_local_ack(local_ack); RET_INVALID; } } if (msg_send(&local_ack->dst, local_ack->buffer, local_ack->buffer_len)<0){ /* hopefully will succeed on next 2xx retransmission */ ERR("failed to send local ACK (T@%p).\n", trans); ret = -1; goto fin; } else { INIT_TMCB_ONSEND_PARAMS(onsend_params, 0, 0, &trans->uac[0].request, &local_ack->dst, local_ack->buffer, local_ack->buffer_len, TMCB_LOCAL_F, 0 /* branch */, TYPE_LOCAL_ACK); run_trans_callbacks_off_params(TMCB_REQUEST_SENT, trans, &onsend_params); } ret = 0; fin: /* TODO: ugly! */ /* FIXME: the T had been obtain by t_lookup_ident()'ing for it, so, it is * ref-counted. The t_unref() can not be used, as it requests a valid SIP * message (all available might be the reply, but if AS goes wrong and * tries to ACK before the final reply is received, we still have to * lookup the T to find this out). */ UNREF( trans ); return ret; #undef RET_INVALID }