rem: callback_event( TMCB_REPLY, p_msg );
add: callback_event( TMCB_REPLY, T, p_msg );
context: int t_on_reply( struct sip_msg  *p_msg ){	int branch, msg_status, msg_class, save_clone;	int local_cancel;	int relay;	int start_fr = 0;	int is_invite;	/* retransmission structure of outbound reply and request */	struct retr_buf *rb=0;	char *buf=0, *ack=0;	/* length of outbound reply */	unsigned int res_len, ack_len;	/* buffer length (might be somewhat larger than message size */	unsigned int alloc_len;	str *str_foo;	struct socket_info* send_sock;	/* make sure we know the assosociated tranaction ... */	if (t_check( p_msg  , &branch , &local_cancel)==-1)		return 1;	/* ... if there is no such, tell the core router to forward statelessly */	if ( T<=0 ) return 1;	DBG("DEBUG: t_on_reply: org. status uas=%d, uac[%d]=%d loca_cancel=%d)\n",		T->uas.status, branch, T->uac[branch].status, local_cancel);	/* special cases (local cancel reply) -bogdan */	if (local_cancel==1)	{		reset_timer( hash_table, &(T->uac[branch].request.retr_timer));		if ( p_msg->REPLY_STATUS>=200 )			reset_timer(hash_table,&(T->uac[branch].request.fr_timer));		goto error;	}	/* do we have via2 ? - maybe we'll need it for forwarding -bogdan*/	if ((p_msg->via2==0) || (p_msg->via2->error!=VIA_PARSE_OK)){		/* no second via => error */		LOG(L_ERR, "ERROR: t_on_reply: no 2nd via found in reply\n");		goto error;	}	msg_status=p_msg->REPLY_STATUS;	msg_class=REPLY_CLASS(p_msg);	is_invite= T->uas.request->REQ_METHOD==METHOD_INVITE;#ifdef _DONT_DO_IT_MAN/*  generate the retrans buffer, make a simplified	assumption everything but 100 will be fwd-ed;	sometimes it will result in useless CPU cycles	but mostly the assumption holds and allows the	work to be done out of criticial lock region */	if (msg_status==100 && T->uac[branch].status)		buf=0;	else {		/* buf maybe allo'ed*/		buf = build_res_buf_from_sip_res ( p_msg, &res_len);		if (!buf) {			LOG(L_ERR, "ERROR: t_on_reply_received: "			"no mem for outbound reply buffer\n");			goto error;		}	}#endif	/* *** stop timers *** */	/* stop retransmission */	reset_timer( hash_table, &(T->uac[branch].request.retr_timer));	/* stop final response timer only if I got a final response */	if ( msg_class>1 )		reset_timer( hash_table, &(T->uac[branch].request.fr_timer));	LOCK_REPLIES( T );	/* if a got the first prov. response for an INVITE ->	   change FR_TIME_OUT to INV_FR_TIME_UT */	start_fr = !T->uac[branch].rpl_received && msg_class==1 && is_invite;	/* *** store and relay message as needed *** */	relay = t_should_relay_response( T , msg_status, branch, &save_clone );	DBG("DEBUG: t_on_reply: branch=%d, save=%d, relay=%d\n",		branch, save_clone, relay );	if (save_clone)	{		str_foo = &(T->uac[branch].tag);		str_foo->s = shm_resize(str_foo->s, (str_foo?0:TAG_OVERBUFFER_LEN) +			get_to(p_msg)->tag_value.len);		if (!str_foo->s)		{			LOG( L_ERR , "ERROR: t_on_reply: connot alocate memory!\n");			goto error1;		}		/* when forking, replies greater then 300 are saved */		if ((T->nr_of_outgoings>1 || T->uac[T->nr_of_outgoings].uri.s)			&& msg_status>=300 )		{			DBG("DEBUG: t_on_reply: saving reply! \n");			str_foo = &(T->uac[branch].rpl_buffer);			str_foo->s = shm_resize(str_foo->s, res_len+				(str_foo->s?0:REPLY_OVERBUFFER_LEN) );			if (!str_foo->s)			{				LOG( L_ERR , "ERROR: t_on_reply: connot alocate memory!\n");				goto error1;			}			memcpy(str_foo->s,buf,res_len);			str_foo->len = res_len;		}		/*copy the TO tag from reply*/		T->uac[branch].tag.len = get_to(p_msg)->tag_value.len;		memcpy( T->uac[branch].tag.s, get_to(p_msg)->tag_value.s,			T->uac[branch].tag.len );		T->uac[branch].rpl_received = 1;		T->uac[branch].status = msg_status;	}	rb = & T->uas.response;	if (relay >= 0  && (relay=check_for_no_response(T,msg_status,relay))>=0 ) {		buf = build_res_buf_from_sip_res ( p_msg, &res_len);		if (!buf) {			UNLOCK_REPLIES( T );			start_fr = 1;			LOG(L_ERR, "ERROR: t_on_reply_received: "				"no mem for outbound reply buffer\n");			goto error1;		}		callback_event( TMCB_REPLY_IN, p_msg );		if (relay!=branch)		{			str_foo = &(T->uac[relay].rpl_buffer);			if (buf) pkg_free(buf);			buf = (char*)pkg_malloc(str_foo->len);			if (!buf)			{				UNLOCK_REPLIES( T );				start_fr = 1;				LOG(L_ERR, "ERROR: t_on_reply: cannot alloc pkg mem\n");				goto error1;			}			memcpy( buf , str_foo->s , str_foo->len );			res_len = str_foo->len;		}		/* if there is no reply yet, initialize the structure */		if ( ! rb->buffer ) {			/*init retrans buffer*/			if (update_sock_struct_from_via( &(rb->to),p_msg->via2 )==-1) {				UNLOCK_REPLIES( T );				start_fr = 1;				LOG(L_ERR, "ERROR: t_on_reply: cannot lookup reply dst: %s\n",					p_msg->via2->host.s );				goto error1;			}			send_sock=get_send_socket(&rb->to);			if (send_sock==0) {				UNLOCK_REPLIES( T );				LOG(L_ERR, "ERROR: t_on_reply: cannot fwd to af %d "					"no socket\n", rb->to.s.sa_family);				start_fr=1;				goto error1;			}			/* rb->to.sin_family = AF_INET; */			rb->send_sock=send_sock;			rb->activ_type = p_msg->REPLY_STATUS;			/* allocate something more for the first message;			   subsequent messages will be longer and buffer			   reusing will save us a malloc lock */			alloc_len = res_len + REPLY_OVERBUFFER_LEN ;		}else{			alloc_len = res_len;		}		/* puts the reply's buffer to uas.response */		if (! (rb->buffer = (char*)shm_resize( rb->buffer, alloc_len ))) {			UNLOCK_REPLIES( T );			start_fr = 1;			LOG(L_ERR, "ERROR: t_on_reply: cannot alloc shmem\n");			goto error1;		}		rb->buffer_len = res_len;		memcpy( rb->buffer, buf, res_len );		/* update the status ... */		T->uas.status = p_msg->REPLY_STATUS;		T->uas.tag=&(T->uac[relay].tag);		if (T->uas.status >=200 && T->relaied_reply_branch==-1 )				T->relaied_reply_branch = relay;	}; /* if relay ... */	UNLOCK_REPLIES( T );	if (relay >= 0) {		SEND_PR_BUFFER( rb, buf, res_len );		t_update_timers_after_sending_reply( rb );		callback_event( TMCB_REPLY, p_msg );	}	/* *** ACK handling *** */	if ( is_invite ) {		if ( T->uac[branch].request.ack_len )		{   /*retransmit*/			/* I don't need any additional syncing here -- after ack			   is introduced it's never changed */			DBG("DEBUG: localy cached ACK retranmitted\n");			SEND_ACK_BUFFER( &(T->uac[branch].request) );		} else if (msg_class>2 ) {			/*on a non-200 reply to INVITE*/			DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE:"				"send ACK\n");			ack = build_ack( p_msg, T, branch , &ack_len);			if (ack) {				SEND_PR_BUFFER( &(T->uac[branch].request), ack, ack_len );				/* append to transaction structure */				attach_ack( T, branch, ack , ack_len );			} else {				/* restart FR */				start_fr=1;				DBG("ERROR: t_on_reply: build_ack failed\n");			}		}	} /* is_invite */	/* restart retransmission if a provisional response came for	   a non_INVITE -> retrasmit at RT_T2*/	if ( msg_class==1 && !is_invite )	{		rb->retr_list = RT_T2;		set_timer( hash_table, &(rb->retr_timer), RT_T2 );	}error1:	if (start_fr)		set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );	if (buf) pkg_free( buf );error:	T_UNREF( T );	/* don't try to relay statelessly on error; on troubles, simply do nothing;	   that will make the other party to retransmit; hopefuly, we'll then 	   be better off */	return 0;}