/* function lookups transaction being canceled by CANCEL in p_msg; * it returns: * 0 - transaction wasn't found * T - transaction found */ struct cell* t_lookupOriginalT( struct sip_msg* p_msg ) { struct cell *p_cell; unsigned int hash_index; struct sip_msg *t_msg; struct via_param *branch; int ret; /* already looked for it? */ if (cancelled_T!=T_UNDEFINED) return cancelled_T; /* start searching in the table */ hash_index = p_msg->hash_index; LM_DBG("searching on hash entry %d\n",hash_index ); /* first of all, look if there is RFC3261 magic cookie in branch; if * so, we can do very quick matching and skip the old-RFC bizzar * comparison of many header fields */ if (!p_msg->via1) { LM_ERR("no via\n"); cancelled_T = NULL; return 0; } branch=p_msg->via1->branch; if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN && memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) { /* huhuhu! the cookie is there -- let's proceed fast */ LOCK_HASH(hash_index); ret=matching_3261(p_msg, &p_cell, /* we are seeking the original transaction -- * skip CANCEL transactions during search */ METHOD_CANCEL); if (ret==1) goto found; else goto notfound; } /* no cookies --proceed to old-fashioned pre-3261 t-matching */ LOCK_HASH(hash_index); /* all the transactions from the entry are compared */ for (p_cell=get_tm_table()->entrys[hash_index].first_cell; p_cell; p_cell = p_cell->next_cell ) { t_msg = p_cell->uas.request; if (!t_msg) continue; /* skip UAC transactions */ /* we don't cancel CANCELs ;-) */ if (t_msg->REQ_METHOD==METHOD_CANCEL) continue; /* check lengths now */ if (!EQ_LEN(callid)) continue; if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) continue; if (!EQ_LEN(from)) continue; #ifdef CANCEL_TAG if (!EQ_LEN(to)) continue; #else /* relaxed matching -- we don't care about to-tags anymore, * many broken UACs screw them up and ignoring them does not * actually hurt */ if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len) continue; #endif if (ruri_matching && !EQ_REQ_URI_LEN) continue; if (via1_matching && !EQ_VIA_LEN(via1)) continue; /* check the content now */ if (!EQ_STR(callid)) continue; if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,get_cseq(p_msg)->number.len)!=0) continue; if (!EQ_STR(from)) continue; #ifdef CANCEL_TAG if (!EQ_STR(to)) continue; #else if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s, get_to(t_msg)->uri.len)!=0) continue; #endif if (ruri_matching && !EQ_REQ_URI_STR) continue; if (via1_matching && !EQ_VIA_STR(via1)) continue; /* found */ goto found; } notfound: /* no transaction found */ LM_DBG("no CANCEL matching found! \n" ); UNLOCK_HASH(hash_index); cancelled_T = NULL; LM_DBG("t_lookupOriginalT completed\n"); return 0; found: LM_DBG("canceled transaction found (%p)! \n",p_cell ); cancelled_T = p_cell; REF_UNSAFE( p_cell ); UNLOCK_HASH(hash_index); /* run callback */ run_trans_callbacks( TMCB_TRANS_CANCELLED, cancelled_T, p_msg, 0,0); LM_DBG("t_lookupOriginalT completed\n"); return p_cell; }
int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) { struct cell *p_cell; unsigned int isACK; struct sip_msg *t_msg; struct via_param *branch; int match_status; isACK = p_msg->REQ_METHOD==METHOD_ACK; if (isACK) { if (e2eack_T==NULL) return -1; if (e2eack_T!=T_UNDEFINED) return -2; } /* parse all*/ if (check_transaction_quadruple(p_msg)==0) { LM_ERR("too few headers\n"); set_t(0); /* stop processing */ return 0; } /* start searching into the table */ if (!p_msg->hash_index) p_msg->hash_index=tm_hash( p_msg->callid->body , get_cseq(p_msg)->number ) ; LM_DBG("start searching: hash=%d, isACK=%d\n", p_msg->hash_index,isACK); /* first of all, look if there is RFC3261 magic cookie in branch; if * so, we can do very quick matching and skip the old-RFC bizzar * comparison of many header fields */ if (!p_msg->via1) { LM_ERR("no via\n"); set_t(0); return 0; } branch=p_msg->via1->branch; if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN && memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) { /* huhuhu! the cookie is there -- let's proceed fast */ LOCK_HASH(p_msg->hash_index); match_status=matching_3261(p_msg,&p_cell, /* skip transactions with different method; otherwise CANCEL * would match the previous INVITE trans. */ isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD); switch(match_status) { case 0: goto notfound; /* no match */ case 1: goto found; /* match */ case 2: goto e2e_ack; /* e2e proxy ACK */ } } /* ok -- it's ugly old-fashioned transaction matching -- it is * a bit simplified to be fast -- we don't do all the comparisons * of parsed uri, which was simply too bloated */ LM_DBG("proceeding to pre-RFC3261 transaction matching\n"); /* lock the whole entry*/ LOCK_HASH(p_msg->hash_index); /* all the transactions from the entry are compared */ for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell; p_cell; p_cell = p_cell->next_cell ) { t_msg = p_cell->uas.request; if (!t_msg) continue; /* skip UAC transactions */ if (!isACK) { /* compare lengths first */ if (!EQ_LEN(callid)) continue; if (!EQ_LEN(cseq)) continue; if (!EQ_LEN(from)) continue; if (!EQ_LEN(to)) continue; if (ruri_matching && !EQ_REQ_URI_LEN) continue; if (via1_matching && !EQ_VIA_LEN(via1)) continue; /* length ok -- move on */ if (!EQ_STR(callid)) continue; if (!EQ_STR(cseq)) continue; if (!EQ_STR(from)) continue; if (!EQ_STR(to)) continue; if (ruri_matching && !EQ_REQ_URI_STR) continue; if (via1_matching && !EQ_VIA_STR(via1)) continue; /* request matched ! */ LM_DBG("non-ACK matched\n"); goto found; } else { /* it's an ACK request*/ /* ACK's relate only to INVITEs - and we look only for 2 types of * INVITEs : (a) negative INVITEs or (b) pozitive UAS INVITEs */ if ( t_msg->REQ_METHOD!=METHOD_INVITE || !(p_cell->uas.status>=300 || (p_cell->nr_of_outgoings==0 && p_cell->uas.status>=200)) ) continue; /* From|To URI , CallID, CSeq # must be always there */ /* compare lengths now */ if (!EQ_LEN(callid)) continue; /* CSeq only the number without method ! */ if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) continue; if (! EQ_LEN(from)) continue; /* To only the uri -- to many UACs screw up tags */ if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len) continue; if (!EQ_STR(callid)) continue; if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s, get_cseq(p_msg)->number.len)!=0) continue; if (!EQ_STR(from)) continue; if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s, get_to(t_msg)->uri.len)!=0) continue; if (p_cell->uas.status<300) { /* it's a 2xx local UAS transaction */ if (dlg_matching(p_cell, p_msg)) goto e2e_ack; continue; } /* it is not an e2e ACK/200 -- perhaps it is * local negative case; in which case we will want * more elements to match: r-uri and via; allow * mismatching r-uri as an config option for broken * UACs */ if (ruri_matching && !EQ_REQ_URI_LEN ) continue; if (via1_matching && !EQ_VIA_LEN(via1)) continue; if (ruri_matching && !EQ_REQ_URI_STR) continue; if (via1_matching && !EQ_VIA_STR(via1)) continue; /* wow -- we survived all the check! we matched! */ LM_DBG("non-2xx ACK matched\n"); goto found; } /* ACK */ } /* synonym loop */ notfound: /* no transaction found */ set_t(0); e2eack_T = NULL; if (!leave_new_locked || isACK) { UNLOCK_HASH(p_msg->hash_index); } LM_DBG("no transaction found\n"); return -1; e2e_ack: REF_UNSAFE( p_cell ); UNLOCK_HASH(p_msg->hash_index); e2eack_T = p_cell; set_t(0); LM_DBG("e2e proxy ACK found\n"); return -2; found: set_t(p_cell); REF_UNSAFE( T ); set_kr(REQ_EXIST); UNLOCK_HASH( p_msg->hash_index ); LM_DBG("transaction found (T=%p)\n",T); return 1; }
/* atomic "new_tran" construct; it returns: <0 on error +1 if a request did not match a transaction - it that was an ack, the calling function shall forward statelessly - otherwise it means, a new transaction was introduced and the calling function shall reply/relay/whatever_appropriate 0 on retransmission */ int t_newtran( struct sip_msg* p_msg, int full_uas ) { int lret, my_err; context_p ctx_backup; /* is T still up-to-date ? */ LM_DBG("transaction on entrance=%p\n",T); if ( T && T!=T_UNDEFINED ) { LM_DBG("transaction already in process %p\n", T ); return E_SCRIPT; } T = T_UNDEFINED; /* first of all, parse everything -- we will store in shared memory and need to have all headers ready for generating potential replies later; parsing later on demand is not an option since the request will be in shmem and applying parse_headers to it would intermix shmem with pkg_mem */ if (parse_headers(p_msg, HDR_EOH_F, 0 )<0) { LM_ERR("parse_headers failed\n"); return E_BAD_REQ; } if ((p_msg->parsed_flag & HDR_EOH_F)!=HDR_EOH_F) { LM_ERR("EoH not parsed\n"); return E_OUT_OF_MEM; } /* t_lookup_requests attempts to find the transaction; it also calls check_transaction_quadruple -> it is safe to assume we have from/callid/cseq/to */ lret = t_lookup_request( p_msg, 1 /* leave locked if not found */ ); /* on error, pass the error in the stack ... nothing is locked yet if 0 is returned */ if (lret==0) return E_BAD_TUPEL; /* transaction found, it's a retransmission */ if (lret>0) { if (p_msg->REQ_METHOD==METHOD_ACK) { t_release_transaction(T); } else { t_retransmit_reply(T); } /* things are done -- return from script */ return 0; } /* from now on, be careful -- hash table is locked */ if (lret==-2) { /* was it an e2e ACK ? if so, trigger a callback */ if (e2eack_T->relaied_reply_branch==-2) { /* if a ACK for a local replied transaction, release the INVITE transaction and break the script -> simply absorb the ACK request */ t_release_transaction(e2eack_T); return 0; } LM_DBG("building branch for end2end ACK - flags=%X\n",e2eack_T->flags); /* to ensure unigueness acros time and space, compute the ACK * branch in the same maner as for INVITE, but put a t->branch * value that cannot exist for that INVITE - as it is compute as * an INVITE, it will not overlapp with other INVITEs or requests. * But the faked value for t->branch guarantee no overalap with * corresponding INVITE --bogdan */ if (!t_calc_branch(e2eack_T, e2eack_T->nr_of_outgoings+1, p_msg->add_to_branch_s, &p_msg->add_to_branch_len )) { LM_ERR("ACK branch computation failed\n"); } return 1; } /* transaction not found, it's a new request (lret<0, lret!=-2); establish a new transaction ... */ if (p_msg->REQ_METHOD==METHOD_ACK) /* ... unless it is in ACK */ return 1; my_err=new_t(p_msg, full_uas); if (my_err<0) { LM_ERR("new_t failed\n"); goto new_err; } UNLOCK_HASH(p_msg->hash_index); /* now, when the transaction state exists, check if there is a meaningful Via and calculate it; better do it now than later: state is established so that subsequent retransmissions will be absorbed and will not possibly block during Via DNS resolution; doing it later would only burn more CPU as if there is an error, we cannot relay later whatever comes out of the the transaction */ if (!init_rb( &T->uas.response, p_msg)) { LM_ERR("unresolvable via1\n"); put_on_wait( T ); t_unref(p_msg); return E_BAD_VIA; } if (auto_100trying && p_msg->REQ_METHOD==METHOD_INVITE) { ctx_backup = current_processing_ctx; current_processing_ctx = NULL; t_reply( T, p_msg , 100 , &relay_reason_100); current_processing_ctx = ctx_backup; } return 1; new_err: UNLOCK_HASH(p_msg->hash_index); return my_err; }
/* lookup a transaction by callid and cseq, parameters are pure * header field content only, e.g. "[email protected]" and "11" */ int t_lookup_callid(struct cell ** trans, str callid, str cseq) { struct cell* p_cell; unsigned int hash_index; /* I use MAX_HEADER, not sure if this is a good choice... */ char callid_header[MAX_HEADER]; char cseq_header[MAX_HEADER]; /* save return value of print_* functions here */ char* endpos; UNUSED(endpos); /* need method, which is always INVITE in our case */ /* CANCEL is only useful after INVITE */ str invite_method; char* invite_string = INVITE; invite_method.s = invite_string; invite_method.len = INVITE_LEN; /* lookup the hash index where the transaction is stored */ hash_index=tm_hash(callid, cseq); if(hash_index >= TM_TABLE_ENTRIES){ LM_ERR("invalid hash_index=%u\n",hash_index); return -1; } /* create header fields the same way tm does itself, then compare headers */ endpos = print_callid_mini(callid_header, callid); LM_DBG("created comparable call_id header field: >%.*s<\n", (int)(endpos - callid_header), callid_header); endpos = print_cseq_mini(cseq_header, &cseq, &invite_method); LM_DBG("created comparable cseq header field: >%.*s<\n", (int)(endpos - cseq_header), cseq_header); LOCK_HASH(hash_index); /* all the transactions from the entry are compared */ p_cell = get_tm_table()->entrys[hash_index].first_cell; for ( ; p_cell; p_cell = p_cell->next_cell ) { /* compare complete header fields, casecmp to make sure invite=INVITE */ LM_DBG(" <%.*s> <%.*s>\n", p_cell->callid.len, p_cell->callid.s, p_cell->cseq_n.len,p_cell->cseq_n.s); if ( (strncmp(callid_header, p_cell->callid.s, p_cell->callid.len) == 0) && (strncasecmp(cseq_header, p_cell->cseq_n.s, p_cell->cseq_n.len) == 0) ) { LM_DBG("we have a match: callid=>>%.*s<< cseq=>>%.*s<<\n", p_cell->callid.len,p_cell->callid.s, p_cell->cseq_n.len, p_cell->cseq_n.s); REF_UNSAFE(p_cell); UNLOCK_HASH(hash_index); set_t(p_cell); *trans=p_cell; LM_DBG("transaction found.\n"); return 1; } LM_DBG("NO match: callid=%.*s cseq=%.*s\n", p_cell->callid.len, p_cell->callid.s, p_cell->cseq_n.len, p_cell->cseq_n.s); } UNLOCK_HASH(hash_index); LM_DBG("transaction not found.\n"); return -1; }
/* WARNING: - dst_cell contains the created cell, but it is un-referenced * (before using it make sure you REF() it first) * - if ACK (method==ACK), a cell will be created but it will not * be added in the hash table (should be either deleted by the * caller) */ static inline int t_uac_prepare(uac_req_t *uac_r, struct retr_buf **dst_req, struct cell **dst_cell) { struct dest_info dst; struct cell *new_cell; struct retr_buf *request; char* buf; int buf_len, ret; unsigned int hi; int is_ack; ticks_t lifetime; #ifdef USE_DNS_FAILOVER struct dns_srv_handle dns_h; #endif long nhtype; #ifdef WITH_EVENT_LOCAL_REQUEST struct cell *backup_t; int backup_branch; unsigned int backup_msgid; static struct sip_msg lreq; char *buf1; int buf_len1; int sflag_bk; int backup_route_type; #endif snd_flags_t snd_flags; tm_xlinks_t backup_xd; tm_xdata_t local_xd; ret=-1; hi=0; /* make gcc happy */ /*if (dst_req) *dst_req = NULL;*/ is_ack = (((uac_r->method->len == 3) && (memcmp("ACK", uac_r->method->s, 3)==0)) ? 1 : 0); /*** added by dcm * - needed by external ua to send a request within a dlg */ if ((nhtype = w_calculate_hooks(uac_r->dialog)) < 0) /* if err's returned, the message is incorrect */ goto error2; if (!uac_r->dialog->loc_seq.is_set) { /* this is the first request in the dialog, set cseq to default value now - Miklos */ uac_r->dialog->loc_seq.value = DEFAULT_CSEQ; uac_r->dialog->loc_seq.is_set = 1; } DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",uac_r->dialog->hooks.next_hop->len, uac_r->dialog->hooks.next_hop->s); /* new message => take the dialog send_socket if set, or the default send_socket if not*/ SND_FLAGS_INIT(&snd_flags); #ifdef USE_DNS_FAILOVER if (cfg_get(core, core_cfg, use_dns_failover)){ dns_srv_handle_init(&dns_h); if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, snd_flags, uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ dns_srv_handle_put(&dns_h); ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } dns_srv_handle_put(&dns_h); /* not needed anymore */ }else{ if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, snd_flags, uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } } #else /* USE_DNS_FAILOVER */ if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags, uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){ ser_error = E_NO_SOCKET; ret=ser_error; LOG(L_ERR, "t_uac: no socket found\n"); goto error2; } #endif /* USE_DNS_FAILOVER */ /* build cell sets X/AVP lists to new transaction structure * => bakup in a tmp struct and restore afterwards */ memset(&local_xd, 0, sizeof(tm_xdata_t)); tm_xdata_replace(&local_xd, &backup_xd); new_cell = build_cell(0); tm_xdata_replace(0, &backup_xd); if (!new_cell) { ret=E_OUT_OF_MEM; LOG(L_ERR, "t_uac: short of cell shmem\n"); goto error2; } if (uac_r->method->len==INVITE_LEN && memcmp(uac_r->method->s, INVITE, INVITE_LEN)==0){ new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags|=T_AUTO_INV_100 & (!cfg_get(tm, tm_cfg, tm_auto_inv_100) -1); #ifdef WITH_AS_SUPPORT if (uac_r->cb_flags & TMCB_DONT_ACK) new_cell->flags |= T_NO_AUTO_ACK; #endif lifetime=cfg_get(tm, tm_cfg, tm_max_inv_lifetime); }else lifetime=cfg_get(tm, tm_cfg, tm_max_noninv_lifetime); new_cell->flags |= T_IS_LOCAL_FLAG; /* init timers hack, new_cell->fr_timer and new_cell->fr_inv_timer * must be set, or else the fr will happen immediately * we can't call init_new_t() because we don't have a sip msg * => we'll ignore t_set_fr() or avp timer value and will use directly the * module params fr_inv_timer and fr_timer -- andrei */ new_cell->fr_timeout=cfg_get(tm, tm_cfg, fr_timeout); new_cell->fr_inv_timeout=cfg_get(tm, tm_cfg, fr_inv_timeout); new_cell->end_of_life=get_ticks_raw()+lifetime; #ifdef TM_DIFF_RT_TIMEOUT /* same as above for retransmission intervals */ new_cell->rt_t1_timeout_ms = cfg_get(tm, tm_cfg, rt_t1_timeout_ms); new_cell->rt_t2_timeout_ms = cfg_get(tm, tm_cfg, rt_t2_timeout_ms); #endif set_kr(REQ_FWDED); request = &new_cell->uac[0].request; request->dst = dst; request->flags |= nhtype; if (!is_ack) { #ifdef TM_DEL_UNREF INIT_REF(new_cell, 1); /* ref'ed only from the hash */ #endif hi=dlg2hash(uac_r->dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); } buf = build_uac_req(uac_r->method, uac_r->headers, uac_r->body, uac_r->dialog, 0, new_cell, &buf_len, &dst); if (!buf) { LOG(L_ERR, "t_uac: Error while building message\n"); ret=E_OUT_OF_MEM; goto error1; } #ifdef WITH_EVENT_LOCAL_REQUEST if (unlikely(goto_on_local_req>=0)) { DBG("executing event_route[tm:local-request]\n"); if(likely(build_sip_msg_from_buf(&lreq, buf, buf_len, inc_msg_no()) == 0)) { /* fill some field in sip_msg */ if (unlikely(set_dst_uri(&lreq, uac_r->dialog->hooks.next_hop))) { LM_ERR("failed to set dst_uri"); free_sip_msg(&lreq); } else { struct onsend_info onsnd_info; lreq.force_send_socket = uac_r->dialog->send_sock; lreq.rcv.proto = dst.send_sock->proto; lreq.rcv.src_ip = dst.send_sock->address; lreq.rcv.src_port = dst.send_sock->port_no; lreq.rcv.dst_port = su_getport(&dst.to); su2ip_addr(&lreq.rcv.dst_ip, &dst.to); lreq.rcv.src_su=dst.send_sock->su; lreq.rcv.bind_address=dst.send_sock; #ifdef USE_COMP lreq.rcv.comp=dst.comp; #endif /* USE_COMP */ sflag_bk = getsflags(); tm_xdata_swap(new_cell, &backup_xd, 0); onsnd_info.to=&dst.to; onsnd_info.send_sock=dst.send_sock; onsnd_info.buf=buf; onsnd_info.len=buf_len; p_onsend=&onsnd_info; /* run the route */ backup_route_type = get_route_type(); set_route_type(LOCAL_ROUTE); /* set T to the current transaction */ backup_t=get_t(); backup_branch=get_t_branch(); backup_msgid=global_msg_id; /* fake transaction and message id */ global_msg_id=lreq.id; set_t(new_cell, T_BR_UNDEFINED); run_top_route(event_rt.rlist[goto_on_local_req], &lreq, 0); /* restore original environment */ set_t(backup_t, backup_branch); global_msg_id=backup_msgid; set_route_type( backup_route_type ); p_onsend=0; /* restore original environment */ tm_xdata_swap(new_cell, &backup_xd, 1); setsflagsval(sflag_bk); if (unlikely(lreq.new_uri.s)) { pkg_free(lreq.new_uri.s); lreq.new_uri.s=0; lreq.new_uri.len=0; } if (unlikely(lreq.dst_uri.s)) { pkg_free(lreq.dst_uri.s); lreq.dst_uri.s=0; lreq.dst_uri.len=0; } if (unlikely(lreq.add_rm || lreq.body_lumps)) { LM_DBG("apply new updates to sip msg\n"); buf1 = build_req_buf_from_sip_req(&lreq, (unsigned int*)&buf_len1, &dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE| BUILD_IN_SHM); if (likely(buf1)){ shm_free(buf); buf = buf1; buf_len = buf_len1; /* a possible change of the method is not handled! */ } } lreq.buf=0; /* covers the obsolete DYN_BUF */ free_sip_msg(&lreq); } } } #endif new_cell->method.s = buf; new_cell->method.len = uac_r->method->len; request->buffer = buf; request->buffer_len = buf_len; new_cell->nr_of_outgoings++; /* Register the callbacks after everything is successful and nothing can fail. Otherwise the callback parameter would be freed twise, once from TMCB_DESTROY, and again because of the negative return code. */ if(uac_r->cb && insert_tmcb(&(new_cell->tmcb_hl), uac_r->cb_flags, *(uac_r->cb), uac_r->cbp, NULL)!=1){ ret=E_OUT_OF_MEM; LOG(L_ERR, "t_uac: short of tmcb shmem\n"); goto error1; } if (has_local_reqin_tmcbs()) run_local_reqin_callbacks(new_cell, 0, 0); #ifdef DIALOG_CALLBACKS run_trans_dlg_callbacks(uac_r->dialog, new_cell, request); #endif /* DIALOG_CALLBACKS */ if (dst_req) *dst_req = request; if (dst_cell) *dst_cell = new_cell; else if(is_ack && dst_req==0){ free_cell(new_cell); } return 1; error1: if (!is_ack) { LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); #ifdef TM_DEL_UNREF UNREF_FREE(new_cell); }else #else } #endif free_cell(new_cell); error2: return ret; }