2
0
Эх сурвалжийг харах

- global callbacks replaced by callbacks per transaction
- per type callback list merged into a single one
- TMCB_ON_FAILURE callback type addded
- completion callback used by t_uac merged into transaction callbacks as
TMCB_LOCAL_COMPLETED

Bogdan-Andrei Iancu 22 жил өмнө
parent
commit
a70eb29888

+ 12 - 10
modules/tm/h_table.c

@@ -34,6 +34,8 @@
  * 2003-04-04  bug_fix: REQ_IN callback not called for local 
  *             UAC transactions (jiri)
  * 2003-09-12  timer_link->tg will be set only if EXTRA_DEBUG (andrei)
+ * 2003-12-04  global callbacks replaceed with callbacks per transaction;
+ *             completion callback merged into them as LOCAL_COMPETED (bogdan)
  */
 
 #include "defs.h"
@@ -106,6 +108,7 @@ void free_cell( struct cell* dead_cell )
 	int i;
 	struct sip_msg *rpl;
 	struct totag_elem *tt, *foo;
+	struct tm_callback *cbs, *cbs_tmp;
 
 	release_cell_lock( dead_cell );
 	shm_lock();
@@ -116,8 +119,12 @@ void free_cell( struct cell* dead_cell )
 	if ( dead_cell->uas.response.buffer )
 		shm_free_unsafe( dead_cell->uas.response.buffer );
 
-	/* completion callback */
-	if (dead_cell->cbp) shm_free_unsafe(dead_cell->cbp);
+	/* callbacks */
+	for( cbs=dead_cell->tmcb_hl.first ; cbs ; ) {
+		cbs_tmp = cbs;
+		cbs = cbs->next;
+		shm_free_unsafe( cbs_tmp );
+	}
 
 	/* UA Clients */
 	for ( i =0 ; i<dead_cell->nr_of_outgoings;  i++ )
@@ -183,15 +190,10 @@ struct cell*  build_cell( struct sip_msg* p_msg )
 	new_cell->uas.response.retr_timer.payload = &(new_cell->uas.response);
 	new_cell->uas.response.my_T=new_cell;
 
-	/* bogdan - debug */
-	/*fprintf(stderr,"before clone VIA |%.*s|\n",via_len(p_msg->via1),
-		via_s(p_msg->via1,p_msg));*/
-
 	/* enter callback, which may potentially want to parse some stuff,
-	   before the request is shmem-ized
-	*/ 
-    if (p_msg) callback_event(TMCB_REQUEST_IN, new_cell, p_msg,
-            p_msg->REQ_METHOD );
+	 * before the request is shmem-ized */
+	if ( p_msg && has_reqin_tmcbs() )
+		run_reqin_callbacks( new_cell, p_msg, p_msg->REQ_METHOD);
 
 	if (p_msg) {
 		new_cell->uas.request = sip_msg_cloner(p_msg);

+ 6 - 10
modules/tm/h_table.h

@@ -29,6 +29,8 @@
  * 2003-03-16  removed _TOTAG (jiri)
  * 2003-03-06  we keep a list of 200/INV to-tags now (jiri)
  * 2003-03-01  kr set through a function now (jiri)
+ * 2003-12-04  callbacks per transaction added; completion callback
+ *             merge into them as LOCAL_COMPETED (bogdan)
  */
 
 #include "defs.h"
@@ -174,21 +176,15 @@ typedef struct cell
 	   with proxied transactions to inbound request */
 	str from, callid, cseq_n, to;
 	/* a short-cut for remember whether this transaction needs
-	   INVITE-special handling (e.g., CANCEL, ACK, FR...)
-	*/
+	   INVITE-special handling (e.g., CANCEL, ACK, FR...)  */
 	short is_invite;
 	/* method shortcut -- for local transactions, pointer to
 	   outbound buffer, for proxies transactions pointer to
-	   original message; needed for reply matching
-	*/
+	   original message; needed for reply matching */
 	str method;
 
-	/* callback and parameter on completion of local transactions */
-	transaction_cb *completion_cb;
-	/* the parameter stores a pointer to shmem -- it will be released
-	   during freeing transaction too
-	*/
-	void *cbp;
+	/* head of callback list */
+	struct tmcb_head_list tmcb_hl;
 
 	/* how many processes are currently processing this transaction ;
 	   note that only processes working on a request/reply belonging

+ 2 - 0
modules/tm/t_funcs.c

@@ -110,6 +110,8 @@ void tm_shutdown()
 	free_timer_table();
 	DBG("DEBUG: tm_shutdown : removing semaphores\n");
 	lock_cleanup();
+	DBG("DEBUG: tm_shutdown : destroing tmcb lists\n");
+	destroy_tmcb_lists();
 	free_tm_stats();
 	DBG("DEBUG: tm_shutdown : done\n");
 }

+ 4 - 2
modules/tm/t_fwd.c

@@ -39,6 +39,8 @@
  *  2003-03-30  we now watch downstream delivery and if it fails, send an
  *              error message upstream (jiri)
  *  2003-04-14  use protocol from uri (jiri)
+ *  2003-12-04  global TM callbacks switched to per transaction callbacks
+ *              (bogdan)
  */
 
 #include "defs.h"
@@ -83,8 +85,8 @@ char *print_uac_request( struct cell *t, struct sip_msg *i_req,
 	/* ... update uri ... */
 	i_req->new_uri=*uri;
 
-	/* ... give apps a chance to change things ... */
-	callback_event( TMCB_REQUEST_FWDED, t, i_req, -i_req->REQ_METHOD);
+	/* run the specific callbacks for this transaction */
+	run_trans_callbacks( TMCB_REQUEST_FWDED , t, i_req, 0, -i_req->REQ_METHOD);
 
 	/* ... and build it now */
 	buf=build_req_buf_from_sip_req( i_req, len, send_sock, proto );

+ 134 - 27
modules/tm/t_hooks.c

@@ -28,6 +28,9 @@
  * History:
  * --------
  *  2003-03-19  replaced all the mallocs/frees w/ pkg_malloc/pkg_free (andrei)
+ *  2003-12-04  global callbacks moved into transaction callbacks;
+ *              multiple events per callback added; single list per
+ *              transaction for all its callbacks (bogdan)
  */
 
 #include "defs.h"
@@ -38,46 +41,150 @@
 #include "../../error.h"
 #include "../../mem/mem.h"
 #include "t_hooks.h"
+#include "t_lookup.h"
+#include "t_funcs.h"
 
-/* strange things happen if callback_array is static on openbsd */
-struct tm_callback_s* callback_array[ TMCB_END ] = { 0, 0 } ;
-static int callback_id=0;
 
-/* register a callback function 'f' of type 'cbt'; will be called
-   back whenever the event 'cbt' occurs in transaction module
-*/
-int register_tmcb( tmcb_type cbt, transaction_cb f, void *param )
+struct tmcb_head_list* req_in_tmcb_hl = 0;
+
+
+
+int init_tmcb_lists()
+{
+	req_in_tmcb_hl = (struct tmcb_head_list*)shm_malloc
+		( sizeof(struct tmcb_head_list) );
+	if (req_in_tmcb_hl==0) {
+		LOG(L_CRIT,"ERROR:tm:init_tmcb_lists: nomore shared mem\n");
+		return -1;
+	}
+	req_in_tmcb_hl->first = 0;
+	req_in_tmcb_hl->reg_types = 0;
+	return 1;
+}
+
+
+void destroy_tmcb_lists()
 {
-	struct tm_callback_s *cbs;
+	struct tm_callback *cbp, *cbp_tmp;
 
-	if (cbt<0 || cbt>=TMCB_END ) {
-		LOG(L_ERR, "ERROR: register_tmcb: invalid callback type: %d\n",
-			cbt );
-		return E_BUG;
+	if (!req_in_tmcb_hl)
+		return;
+
+	for( cbp=req_in_tmcb_hl->first; cbp ; ) {
+		cbp_tmp = cbp;
+		cbp = cbp->next;
+		if (cbp->param) shm_free( cbp->param );
+		shm_free( cbp_tmp );
 	}
 
-	if (!(cbs=pkg_malloc( sizeof( struct tm_callback_s)))) {
-		LOG(L_ERR, "ERROR: register_tmcb: out of mem\n");
+	shm_free(req_in_tmcb_hl);
+}
+
+
+inline int insert_tmcb(struct tmcb_head_list *cb_list, int types,
+									transaction_cb f, void *param )
+{
+	struct tm_callback *cbp;
+
+	/* build a new callback structure */
+	if (!(cbp=shm_malloc( sizeof( struct tm_callback)))) {
+		LOG(L_ERR, "ERROR:tm:register_tmcb: out of shm. mem\n");
 		return E_OUT_OF_MEM;
 	}
 
-	callback_id++;
-	cbs->id=callback_id;
-	cbs->callback=f;
-	cbs->next=callback_array[ cbt ];
-	cbs->param=param;
-	callback_array[ cbt ]=cbs;
+	/* link it into the proper place... */
+	cbp->next = cb_list->first;
+	cb_list->first = cbp;
+	cb_list->reg_types |= types;
+	/* ... and fill it up */
+	cbp->callback = f;
+	cbp->param = param;
+	cbp->types = types;
+	if (cbp->next)
+		cbp->id = cbp->next->id+1;
+	else
+		cbp->id = 0;
+
+	return 1;
+}
+
+
+
+/* register a callback function 'f' for 'types' mask of events;
+ * will be called back whenever one of the events occurs in transaction module
+ * (global or per transacation, depinding of event type)
+*/
+int register_tmcb( struct sip_msg* p_msg, int types, transaction_cb f,
+																void *param )
+{
+	struct cell* t;
+	struct tmcb_head_list *cb_list;
+
+	/* are the callback types valid?... */
+	if ( types<0 || types>=TMCB_MAX ) {
+		LOG(L_CRIT, "BUG:tm:register_tmcb: invalid callback types: mask=%d\n",
+			types);
+		return E_BUG;
+	}
+	if (types&TMCB_REQUEST_IN) {
+		if (types!=TMCB_REQUEST_IN) {
+			LOG(L_CRIT, "BUG:tm:register_tmcb: callback type TMCB_REQUEST_IN "
+				"can't be register along with types\n");
+			return E_BUG;
+		}
+		cb_list = req_in_tmcb_hl;
+	} else {
+		/* look for the transaction */
+		if ( t_check(p_msg,0)!=1 ){
+			LOG(L_CRIT,"BUG:tm:register_tmcb: no transaction found\n");
+			return E_BUG;
+		}
+		if ( (t=get_t())==0 ) {
+			LOG(L_CRIT,"BUG:tm:register_tmcb: transaction found is NULL\n");
+			return E_BUG;
+		}
+		cb_list = &(t->tmcb_hl);
+	}
+
+	return insert_tmcb( cb_list, types, f, param );
+}
 
-	return callback_id;
+
+void run_trans_callbacks( int type , struct cell *trans,
+						struct sip_msg *req, struct sip_msg *rpl, int code )
+{
+	static struct tmcb_params params = {0,0,0,0};
+	struct tm_callback    *cbp;
+
+	params.req = req;
+	params.rpl = rpl;
+	params.code = code;
+
+	for (cbp=trans->tmcb_hl.first; cbp; cbp=cbp->next)  {
+		if ( (cbp->types)&type ) {
+			DBG("DBG: trans=%p, callback type %d, id %d entered\n",
+				trans, type, cbp->id );
+			params.param = cbp->param;
+			cbp->callback( trans, type, &params );
+		}
+	}
 }
 
-void callback_event( tmcb_type cbt , struct cell *trans,
-	struct sip_msg *msg, int code )
+
+
+void run_reqin_callbacks( struct cell *trans, struct sip_msg *req, int code )
 {
-	struct tm_callback_s *cbs;
+	static struct tmcb_params params = {0,0,0,0};
+	struct tm_callback    *cbp;
 
-	for (cbs=callback_array[ cbt ]; cbs; cbs=cbs->next)  {
-		DBG("DBG: callback type %d, id %d entered\n", cbt, cbs->id );
-		cbs->callback( trans, msg, code, cbs->param );
+	params.req = req;
+	params.code = code;
+
+	for (cbp=req_in_tmcb_hl->first; cbp; cbp=cbp->next)  {
+		DBG("DBG: trans=%p, callback type %d, id %d entered\n",
+			trans, cbp->types, cbp->id );
+		params.param = cbp->param;
+		cbp->callback( trans, cbp->types, &params );
 	}
 }
+

+ 83 - 36
modules/tm/t_hooks.h

@@ -26,8 +26,11 @@
  *
  * History:
  * --------
- * 2003-03-16 backwards-compatibility callback names introduced (jiri)
- * 2003-03-06 old callbacks renamed, new one introduced (jiri)
+ * 2003-03-16 : backwards-compatibility callback names introduced (jiri)
+ * 2003-03-06 : old callbacks renamed, new one introduced (jiri)
+ * 2003-12-04 : global callbacks moved into transaction callbacks;
+ *              multiple events per callback added; single list per
+ *              transaction for all its callbacks (bogdan)
  */
 
 
@@ -36,25 +39,20 @@
 
 #include "defs.h"
 
-
 struct sip_msg;
 struct cell;
 
-/* backwards compatibility hooks */
-#define TMCB_REPLY TMCB_RESPONSE_OUT
-#define TMCB_E2EACK TMCB_E2EACK_IN
-#define TMCB_REPLY_IN TMCB_RESPONSE_IN
-#define TMCB_REQUEST_OUT TMCB_REQUEST_FWDED
-#define TMCB_ON_NEGATIVE TMCB_ON_FAILURE
-
-typedef enum { 
-		/* input events */
-		TMCB_RESPONSE_IN=1, TMCB_REQUEST_IN, TMCB_E2EACK_IN, 
-		/* routing decisions in progress */
-		TMCB_REQUEST_FWDED, TMCB_RESPONSE_FWDED, TMCB_ON_FAILURE,
-		/* completion events */
-		TMCB_RESPONSE_OUT, TMCB_LOCAL_COMPLETED, 
-		TMCB_END } tmcb_type;
+
+#define TMCB_REQUEST_IN       (1<<0)
+#define TMCB_RESPONSE_IN      (1<<1)
+#define TMCB_E2EACK_IN        (1<<2)
+#define TMCB_REQUEST_FWDED    (1<<3)
+#define TMCB_RESPONSE_FWDED   (1<<4)
+#define TMCB_ON_FAILURE_RO    (1<<5)
+#define TMCB_ON_FAILURE       (1<<6)
+#define TMCB_RESPONSE_OUT     (1<<7)
+#define TMCB_LOCAL_COMPLETED  (1<<8)
+#define TMCB_MAX              ((1<<9)-1)
 
 /* 
  *  Caution: most of the callbacks work with shmem-ized messages
@@ -65,6 +63,13 @@ typedef enum {
  *  is a non-dereferencable pointer indicating that no message
  *  was received and a timer hit instead.
  *
+ *  All callbacks excepting the TMCB_REQUEST_IN are associates to a
+ *  transaction. It means they will be run only when the event will hint
+ *  the transaction the callbacks were register for.
+ *  TMCB_REQUEST_IN is a global callback - it means it will be run for
+ *  all transactions.
+ *
+ *
  *  Callback description:
  *  ---------------------
  *
@@ -98,6 +103,11 @@ typedef enum {
  *    drops state silently, doesn't use callbacks and expects the
  *    transaction to complete statelessly.
  *
+ *  TMCB_ON_FAILURE_RO -- called on receipt of a reply or timer;
+ *  it means all branches completed with a failure; the callback 
+ *  function MUST not change anything in the transaction (READONLY)
+ *  that's a chance for doing ACC or stuff like this
+ *
  *  TMCB_ON_FAILURE -- called on receipt of a reply or timer;
  *  it means all branches completed with a failure; that's 
  *  a chance for example to add new transaction branches
@@ -139,36 +149,73 @@ typedef enum {
  *  TMCB_LOCAL COMPLETED -- final reply for localy initiated
  *  transaction arrived. Message may be FAKED_REPLY.
  *
- *  TMCB_END	- just a bumper
-
-	see the 'acc' module for an example of callback usage
 
 	note that callbacks MUST be installed before forking
-    (callback lists do not live in shmem and have no access
+	(callback lists do not live in shmem and have no access
 	protection), i.e., at best from mod_init functions.
 
-	also, note: the callback param is currently not used;
-	if whoever wishes to use a callback parameter, use
-	trans->cbp
+	the callback's param MUST be in shared memory and will
+	NOT be freed by TM; you must do it yourself from the
+	callback function id necessary.
 */
 
-typedef void (transaction_cb) ( struct cell* t, struct sip_msg* msg, 
-	int code, void *param );
 
-struct tm_callback_s {
-	int id;
-	transaction_cb* callback;
-	struct tm_callback_s* next;
+/* pack structure with all params passed toa callback function */
+struct tmcb_params {
+	struct sip_msg* req;
+	struct sip_msg* rpl;
+	int code;
 	void *param;
 };
 
+/* callback function prototype */
+typedef void (transaction_cb) (struct cell* t, int type, struct tmcb_params*);
+/* register callback function prototype */
+typedef int (*register_tmcb_f)(struct sip_msg* p_msg, int cb_types,
+		transaction_cb f, void *param);
+
+
+struct tm_callback {
+	int id;                      /* id of this callback - useless */
+	int types;                   /* types of events that trigger the callback*/
+	transaction_cb* callback;    /* callback function */
+	void *param;                 /* param to be passed to callback function */
+	struct tm_callback* next;
+};
+
+struct tmcb_head_list {
+	struct tm_callback *first;
+	int reg_types;
+};
+
+
+extern struct tmcb_head_list*  req_in_tmcb_hl;
+
+
+#define has_tran_tmcbs(_T_, _types_) \
+	( ((_T_)->tmcb_hl.reg_types)|(_types_) )
+#define has_reqin_tmcbs() \
+	( req_in_tmcb_hl->first!=0 )
+
+
+int init_tmcb_lists();
+
+void destroy_tmcb_lists();
+
+
+/* register a callback for several types of events */
+int register_tmcb( struct sip_msg* p_msg, int types, transaction_cb f,
+																void *param );
 
-extern struct tm_callback_s* callback_array[ TMCB_END ];
+/* inserts a callback into the a callback list */
+int insert_tmcb(struct tmcb_head_list *cb_list, int types,
+									transaction_cb f, void *param );
 
-typedef int (*register_tmcb_f)(tmcb_type cbt, transaction_cb f, void *param);
+/* run all transaction callbacks for an event type */
+void run_trans_callbacks( int type , struct cell *trans,
+						struct sip_msg *req, struct sip_msg *rpl, int code );
 
-int register_tmcb( tmcb_type cbt, transaction_cb f, void *param );
-void callback_event( tmcb_type cbt, struct cell *trans,
-	struct sip_msg *msg, int code );
+/* run all REQUEST_IN callbacks */
+void run_reqin_callbacks( struct cell *trans, struct sip_msg *req, int code );
 
 #endif

+ 18 - 15
modules/tm/t_lookup.c

@@ -72,6 +72,8 @@
  * 2003-04-30  t_newtran clean up (jiri)
  * 2003-08-21  request lookups fixed to skip UAC transactions, 
  *             thanks Ed (jiri)
+ * 2003-12-04  global TM callbacks switched to per transaction callbacks
+ *             (bogdan)
  */
 
 
@@ -784,17 +786,19 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
 		 * retransmissions of multiple 200/INV or ACK/200s
 		 */
 		if (p_cell->is_invite && p_msg->REPLY_STATUS>=200 
-				&& p_msg->REPLY_STATUS<300 
-				&& ( (!p_cell->local && 
-					(callback_array[TMCB_RESPONSE_OUT]||
-						callback_array[TMCB_E2EACK_IN]))
-					|| (p_cell->local && callback_array[TMCB_LOCAL_COMPLETED]) )) {
+		&& p_msg->REPLY_STATUS<300 
+		&& ( (!p_cell->local && 
+				has_tran_tmcbs(p_cell,TMCB_RESPONSE_OUT|TMCB_E2EACK_IN) )
+			|| (p_cell->local && has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED))
+		)) {
 			if (parse_headers(p_msg, HDR_TO, 0)==-1) {
 				LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n");
 			}
 		}
-		if (!p_cell->local) 
-			callback_event(TMCB_RESPONSE_IN, T, p_msg, p_msg->REPLY_STATUS);
+		if (!p_cell->local) {
+			run_trans_callbacks( TMCB_RESPONSE_IN, T, T->uas.request, p_msg,
+				p_msg->REPLY_STATUS);
+		}
 		return 1;
 	} /* for cycle */
 
@@ -1051,21 +1055,20 @@ int t_newtran( struct sip_msg* p_msg )
 
 	if (lret==-2) { /* was it an e2e ACK ? if so, trigger a callback */
 		/* no callbacks? complete quickly */
-		if (!callback_array[TMCB_E2EACK_IN]) {
+		if ( !has_tran_tmcbs(t_ack,TMCB_E2EACK_IN) ) {
 			UNLOCK_HASH(p_msg->hash_index);
 			return 1;
 		} 
 		REF_UNSAFE(t_ack);
 		UNLOCK_HASH(p_msg->hash_index);
 		/* we don't call from within REPLY_LOCK -- that introduces
-	   	   a race condition; however, it is so unlikely and the
-	   	   impact is so small (callback called multiple times of
-           multiple ACK/200s received in parallel), that we do not
-	   	    better waste time in locks
-		 */
+		 * a race condition; however, it is so unlikely and the
+		 * impact is so small (callback called multiple times of
+		 * multiple ACK/200s received in parallel), that we do not
+		 * better waste time in locks  */
 		if (unmatched_totag(t_ack, p_msg)) {
-			callback_event( TMCB_E2EACK_IN, t_ack, p_msg, 
-				p_msg->REQ_METHOD );
+			run_trans_callbacks( TMCB_E2EACK_IN , t_ack, p_msg, 0,
+				-p_msg->REQ_METHOD );
 		}
 		UNREF(t_ack);
 		return 1;

+ 124 - 132
modules/tm/t_reply.c

@@ -52,6 +52,8 @@
  *  2003-11-05  flag context updated from failure/reply handlers back
  *              to transaction context (jiri)
  *  2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan)
+ *  2003-12-04  global TM callbacks switched to per transaction callbacks
+ *              (bogdan)
  */
 
 
@@ -102,6 +104,7 @@ static int goto_on_negative=0;
 static int goto_on_reply=0;
 
 
+
 /* we store the reply_route # in private memory which is
    then processed during t_relay; we cannot set this value
    before t_relay creates transaction context or after
@@ -309,11 +312,13 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len,
 	if (code>=200) {
 		if (trans->local) {
 			DBG("DEBUG: local transaction completed from _reply\n");
-			callback_event( TMCB_LOCAL_COMPLETED, trans, FAKED_REPLY, code );
-			if (trans->completion_cb) 
-				trans->completion_cb( trans, FAKED_REPLY, code, trans->cbp);
+			if ( has_tran_tmcbs(trans, TMCB_LOCAL_COMPLETED) )
+				run_trans_callbacks( TMCB_LOCAL_COMPLETED, trans,
+					0, FAKED_REPLY, code);
 		} else {
-			callback_event( TMCB_RESPONSE_OUT, trans, FAKED_REPLY, code );
+			if ( has_tran_tmcbs(trans, TMCB_RESPONSE_OUT) )
+				run_trans_callbacks( TMCB_RESPONSE_OUT, trans,
+					trans->uas.request, FAKED_REPLY, code);
 		}
 
 		cleanup_uac_timers( trans );
@@ -380,45 +385,15 @@ static int _reply( struct cell *trans, struct sip_msg* p_msg,
 }
 
 
-/* create a temporary faked message environment in which a conserved
- * t->uas.request in shmem is partially duplicated to pkgmem
- * to allow pkg-based actions to use it; 
- *
- * if restore parameter is set, the environment is restored to the
- * original setting and return value is unsignificant (always 0); 
- * otherwise  a faked environment if created; if that fails,
- * false is returned
- */
-static int faked_env(struct sip_msg *fake, 
-				struct cell *_t,
-				struct sip_msg *shmem_msg,
-				int _restore )
+/*if msg is set -> it will fake the env. vars conforming with the msg; if NULL
+ * the env. will be restore to original */
+static inline void faked_env( struct cell *t,struct sip_msg *msg)
 {
 	static enum route_mode backup_mode;
 	static struct cell *backup_t;
 	static unsigned int backup_msgid;
 
-	if (_restore) goto restore;
-
-	/* 
-     on_negative_reply faked msg now copied from shmem msg (as opposed
-     to zero-ing) -- more "read-only" actions (exec in particular) will 
-     work from reply_route as they will see msg->from, etc.; caution, 
-     rw actions may append some pkg stuff to msg, which will possibly be 
-     never released (shmem is released in a single block)
-    */
-	memcpy( fake, shmem_msg, sizeof(struct sip_msg));
-
-	/* if we set msg_id to something different from current's message
-       id, the first t_fork will properly clean new branch URIs
-	*/
-	fake->id=shmem_msg->id-1;
-	/* set items, which will be duped to pkg_mem, to zero, so that
-	 * "restore" called on error does not free the original items */
-	fake->add_rm=0;
-	fake->body_lumps=0;
-	fake->new_uri.s=0; fake->new_uri.len=0; 
-
+	if (msg) {
 	/* remember we are back in request processing, but process
 	 * a shmem-ed replica of the request; advertise it in rmode;
 	 * for example t_reply needs to know that
@@ -435,90 +410,109 @@ static int faked_env(struct sip_msg *fake,
 	backup_t=get_t();
 	backup_msgid=global_msg_id;
 	/* fake transaction and message id */
-	global_msg_id=fake->id;
-	set_t(_t);
+		global_msg_id=msg->id;
+		set_t(t);
+	} else {
+		/* restore original environment */
+		set_t(backup_t);
+		global_msg_id=backup_msgid;
+		rmode=backup_mode;
+	}
+}
+
+
+
+/* return 1 if a failure_route processes */
+static inline int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
+																	int code)
+{
+	static struct sip_msg fake_req;
+	struct sip_msg *shmem_msg = t->uas.request;
+
+	/* failure_route for a local UAC? */
+	if (!shmem_msg) {
+		LOG(L_WARN, "Warning: run_failure_handlers: no UAC support\n");
+		return 0;
+	}
+
+	/* don't start faking anything if we don't have to */
+	if ( !has_tran_tmcbs( t, TMCB_ON_FAILURE) && !t->on_negative ) {
+		return 1;
+	}
 
-	/* environment is set up now, try to fake the message */
+	/* on_negative_reply faked msg now copied from shmem msg (as opposed
+	 * to zero-ing) -- more "read-only" actions (exec in particular) will
+	 * work from reply_route as they will see msg->from, etc.; caution,
+	 * rw actions may append some pkg stuff to msg, which will possibly be
+	 * never released (shmem is released in a single block) */
+	memcpy( &fake_req, shmem_msg, sizeof(struct sip_msg));
+
+	/* if we set msg_id to something different from current's message
+	 * id, the first t_fork will properly clean new branch URIs */
+	fake_req.id=shmem_msg->id-1;
 
 	/* new_uri can change -- make a private copy */
 	if (shmem_msg->new_uri.s!=0 && shmem_msg->new_uri.len!=0) {
-		fake->new_uri.s=pkg_malloc(shmem_msg->new_uri.len+1);
-		if (!fake->new_uri.s) {
-			LOG(L_ERR, "ERROR: faked_env: no uri/pkg mem\n");
-			goto restore;
+		fake_req.new_uri.s=pkg_malloc(shmem_msg->new_uri.len+1);
+		if (!fake_req.new_uri.s) {
+			LOG(L_ERR, "ERROR: run_failure_handlers: no uri/pkg mem\n");
+			return 0;
 		}
-		fake->new_uri.len=shmem_msg->new_uri.len;
-		memcpy( fake->new_uri.s, shmem_msg->new_uri.s, 
-			fake->new_uri.len);
-		fake->new_uri.s[fake->new_uri.len]=0;
-	} 
+		fake_req.new_uri.len=shmem_msg->new_uri.len;
+		memcpy( fake_req.new_uri.s, shmem_msg->new_uri.s, 
+			fake_req.new_uri.len);
+		fake_req.new_uri.s[fake_req.new_uri.len]=0;
+	}
 
 	/* create a duplicated lump list to which actions can add
-	 * new pkg items 
-	 */
+	 * new pkg items  */
 	if (shmem_msg->add_rm) {
-		fake->add_rm=dup_lump_list(shmem_msg->add_rm);
-		if (!fake->add_rm) { /* non_emty->empty ... failure */
-			LOG(L_ERR, "ERROR: on_negative_reply: lump dup failed\n");
-			goto restore;
+		fake_req.add_rm=dup_lump_list(shmem_msg->add_rm);
+		if (!fake_req.add_rm) { /* non_emty->empty ... failure */
+			LOG(L_ERR, "ERROR: run_failure_handlers: lump dup failed\n");
+			if (fake_req.new_uri.s) pkg_free(fake_req.new_uri.s);
+			return 0;
 		}
 	}
 
+	/* same for the body lumps */
 	if (shmem_msg->body_lumps) {
-		fake->body_lumps=dup_lump_list(shmem_msg->body_lumps);
-		if (!fake->body_lumps) { /* non_empty->empty ... failure */
-			LOG(L_ERR, "ERROR: on_negative_reply: lump dup failed\n");
-			goto restore;
+		fake_req.body_lumps=dup_lump_list(shmem_msg->body_lumps);
+		if (!fake_req.body_lumps) { /* non_empty->empty ... failure */
+			LOG(L_ERR, "ERROR: on_negative_handlers: lump dup failed\n");
+			free_duped_lump_list(fake_req.add_rm);
+			if (fake_req.new_uri.s) pkg_free(fake_req.new_uri.s);
+			return 0;
 		}
 	}
-	
-	/* success */
-	return 1;
-
-restore:
-	/* restore original environment and destroy faked message */
-	free_duped_lump_list(fake->add_rm);
-	free_duped_lump_list(fake->body_lumps);
-	if (fake->new_uri.s) pkg_free(fake->new_uri.s);
-	set_t(backup_t);
-	global_msg_id=backup_msgid;
-	rmode=backup_mode;
-	/* if failure handler changed flag, update transaction context */
-	shmem_msg->flags=fake->flags;
-	return 0;
-}
 
-/* return 1 if a failure_route processes */
-int failure_route(struct cell *t)
-{
-	struct sip_msg faked_msg;
-	struct sip_msg *orig_request;
-
-	/* don't do anything if we don't have to */
-	if (!t->on_negative) return 0;
-	orig_request=t->uas.request;
-	/* failure_route for a local UAC? */
-	if (!orig_request) {
-		LOG(L_WARN, "Warning: failure_route: no UAC support\n");
-		return 0;
-	}
+	/* fake also the env. conforming to the fake msg */
+	faked_env( t, &fake_req);
+	/* DONE with faking ;-) -> run the failure handlers */
 
-	/* if fake message creation failes, return error too */
-	if (!faked_env(&faked_msg, t, orig_request, 0 /* create fake */ )) {
-		LOG(L_ERR, "ERROR: on_negative_reply: faked_env failed\n");
-		return 0;
+	if ( has_tran_tmcbs( t, TMCB_ON_FAILURE) ) {
+		run_trans_callbacks( TMCB_ON_FAILURE, t, &fake_req, rpl, code);
 	}
-
+	if (t->on_negative) {
 	/* avoid recursion -- if failure_route forwards, and does not 
 	 * set next failure route, failure_route will not be rentered
 	 * on failure */
 	t_on_negative(0);
 	/* run a reply_route action if some was marked */
-	if (run_actions(failure_rlist[t->on_negative], &faked_msg)<0)
-		LOG(L_ERR, "ERROR: on_negative_reply: "
-			"Error in do_action\n");
-	/* restore original environment */
-	faked_env(&faked_msg, 0, orig_request, 1 );
+		if (run_actions(failure_rlist[t->on_negative], &fake_req)<0)
+			LOG(L_ERR, "ERROR: run_failure_handlers: Error in do_action\n");
+	}
+
+	/* restore original environment and free the fake msg */
+	faked_env( t, 0);
+	free_duped_lump_list(fake_req.add_rm);
+	free_duped_lump_list(fake_req.body_lumps);
+	fake_req.add_rm = fake_req.body_lumps = 0;
+	if (fake_req.new_uri.s) {
+		pkg_free(fake_req.new_uri.s);
+		fake_req.new_uri.s = 0;
+	}
+
 	return 1;
 }
 
@@ -572,7 +566,6 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 	int branch , int *should_store, int *should_relay,
 	branch_bm_t *cancel_bitmap, struct sip_msg *reply )
 {
-	
 	int branch_cnt;
 	int picked_branch;
 	int picked_code;
@@ -630,15 +623,16 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 
 		/* no more pending branches -- try if that changes after
 		   a callback; save banch count to be able to determine
-		   later if new branches were initiated
-		*/
+		   later if new branches were initiated */
 		branch_cnt=Trans->nr_of_outgoings;
-		callback_event( TMCB_ON_FAILURE, Trans, 
-			picked_branch==branch?reply:Trans->uac[picked_branch].reply, 
-			picked_code);
-		/* here, we create a faked environment, from which we
-		 * return to request processing, if marked to do so */
-		failure_route(Trans);
+
+		/* run ON_FAILURE handlers ( route and callbacks) */
+		if ( has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
+		|| Trans->on_negative ) {
+			run_failure_handlers( Trans,
+				picked_branch==branch?reply:Trans->uac[picked_branch].reply, 
+				picked_code);
+		}
 
 		/* look if the callback perhaps replied transaction; it also
 		   covers the case in which a transaction is replied localy
@@ -849,7 +843,7 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
 
 
 	/* remember, what was sent upstream to know whether we are
-	   forwarding a first final reply or not */
+	 * forwarding a first final reply or not */
 
 	/* *** store and relay message as needed *** */
 	reply_status = t_should_relay_response(t, msg_status, branch, 
@@ -866,19 +860,19 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
 
 	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) {
-			callback_event( TMCB_RESPONSE_FWDED, t, p_msg, msg_status );
+		 * 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 bulding the outbound reply from either the current
-	       or a stored message */
+		 * or a stored message */
 		relayed_msg = branch==relay ? p_msg :  t->uac[relay].reply;
 		if (relayed_msg==FAKED_REPLY) {
 			tm_stats->replied_localy++;
@@ -942,9 +936,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
 		t->relaied_reply_branch = relay;
 
 		if (t->is_invite && relayed_msg!=FAKED_REPLY
-				&& relayed_code>=200 && relayed_code < 300
-				&& (callback_array[TMCB_RESPONSE_OUT] ||
-						callback_array[TMCB_E2EACK_IN]))  {
+		&& 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 ... */
@@ -956,8 +949,10 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
 		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) 
-				callback_event( TMCB_RESPONSE_OUT, t, relayed_msg, relayed_code );
+		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 );
 	}
 
@@ -1026,22 +1021,19 @@ enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch,
 		}
 		t->uas.status = winning_code;
 		update_reply_stats( winning_code );
-		if (t->is_invite && winning_msg!=FAKED_REPLY 
-				&& winning_code>=200 && winning_code <300
-				&& (callback_array[TMCB_RESPONSE_OUT] ||
-						callback_array[TMCB_E2EACK_IN]))  {
+		if (t->is_invite && 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) {
-			callback_event( TMCB_LOCAL_COMPLETED, t, winning_msg, 
-				winning_code );
-			if (t->completion_cb) t->completion_cb( t, winning_msg, 
-						winning_code, t->cbp);
+			if ( has_tran_tmcbs(t,TMCB_LOCAL_COMPLETED) )
+				run_trans_callbacks( TMCB_LOCAL_COMPLETED, t, 0,
+					winning_msg, winning_code );
 		}
 	}
 	return reply_status;

+ 0 - 1
modules/tm/t_reply.h

@@ -141,6 +141,5 @@ void tm_init_tags();
 /* selects the branch for fwd-ing the reply */
 int t_pick_branch(int inc_branch, int inc_code, struct cell *t, int *res_code);
 
-
 #endif
 

+ 9 - 5
modules/tm/tm.c

@@ -452,12 +452,12 @@ static int mod_init(void)
 		return -1;
 	}
 
+	/* building the hash table*/
 	if (!init_hash_table()) {
 		LOG(L_ERR, "ERROR: mod_init: initializing hash_table failed\n");
 		return -1;
 	}
 
-
 	/* init static hidden values */
 	init_t();
 
@@ -480,20 +480,24 @@ static int mod_init(void)
 		return -1;
 	}
 
-	/* building the hash table*/
-
 	if (uac_init()==-1) {
 		LOG(L_ERR, "ERROR: mod_init: uac_init failed\n");
 		return -1;
 	}
+
+	if (init_tmcb_lists()!=1) {
+		LOG(L_CRIT, "ERROR:tm:mod_init: failed to init tmcb lists\n");
+		return -1;
+	}
+
+	tm_init_tags();
+
 	/* register post-script clean-up function */
 	register_script_cb( w_t_unref, POST_SCRIPT_CB, 
 			0 /* empty param */ );
 	register_script_cb( script_init, PRE_SCRIPT_CB , 
 			0 /* empty param */ );
 
-	tm_init_tags();
-
 	return 0;
 }
 

+ 0 - 1
modules/tm/tm_load.c

@@ -45,7 +45,6 @@ int load_tm( struct tm_binds *tmb)
 		LOG(L_ERR, LOAD_ERROR "'register_tmcb' not found\n");
 		return -1;
 	}
-
 	if (!( tmb->t_relay_to_tcp=find_export(T_RELAY_TO_TCP, 2, 0)) ) {
 		LOG(L_ERR, LOAD_ERROR "'t_relay_to_tcp' not found\n");
 		return -1;

+ 18 - 19
modules/tm/tm_load.h

@@ -56,6 +56,7 @@
 #define T_RELAY              "t_relay"
 #define T_REPLY              "t_reply"
 #define T_REPLY_WB           "t_reply_with_body"
+#define T_REPLY_UNSAFE       "t_reply_unsafe"
 #define T_ADDBLIND           "t_add_blind"
 #define T_REPLY_UNSAFE       "t_reply_unsafe"
 #define T_FORWARD_NONACK     "t_forward_nonack"
@@ -68,35 +69,33 @@
 #define T_IS_LOCAL           "t_is_local"
 #define T_REQUEST_WITHIN     "request_within"
 #define T_REQUEST_OUTSIDE    "request_outside"
-#define T_GETT				 "t_gett"
+#define T_GETT               "t_gett"
 
 
 
 struct tm_binds {
-	register_tmcb_f register_tmcb;
-	cmd_function    t_relay_to_udp;
-	cmd_function    t_relay_to_tcp;
-	cmd_function    t_relay;
-	treply_f        t_reply;
-	treply_wb_f     t_reply_with_body;
-	tislocal_f      t_is_local;
-	tget_ti_f       t_get_trans_ident;
-	tlookup_ident_f t_lookup_ident;
-	taddblind_f     t_addblind;
-	treply_f        t_reply_unsafe;
-	tfwd_f          t_forward_nonack;
-	reqwith_t       t_request_within;
-	reqout_t        t_request_outside;
-	req_t           t_request;
-	
+	register_tmcb_f  register_tmcb;
+	cmd_function     t_relay_to_udp;
+	cmd_function     t_relay_to_tcp;
+	cmd_function     t_relay;
+	treply_f         t_reply;
+	treply_wb_f      t_reply_with_body;
+	tislocal_f       t_is_local;
+	tget_ti_f        t_get_trans_ident;
+	tlookup_ident_f  t_lookup_ident;
+	taddblind_f      t_addblind;
+	treply_f         t_reply_unsafe;
+	tfwd_f           t_forward_nonack;
+	reqwith_t        t_request_within;
+	reqout_t         t_request_outside;
+	req_t            t_request;
 	new_dlg_uac_f      new_dlg_uac;
 	dlg_response_uac_f dlg_response_uac;
 	new_dlg_uas_f      new_dlg_uas;
 	dlg_request_uas_f  dlg_request_uas;
 	free_dlg_f         free_dlg;
 	print_dlg_f        print_dlg;
-
-	tgett_f			t_gett;
+	tgett_f            t_gett;
 };
 
 

+ 19 - 17
modules/tm/uac.c

@@ -45,6 +45,8 @@
  *  2003-07-08  appropriate log messages in check_params(...), 
  *               call calculate_hooks if next_hop==NULL in t_uac (dcm) 
  *  2003-10-24  updated to the new socket_info lists (andrei)
+ *  2003-12-03  completion filed removed from transaction and uac callbacks
+ *              merged in transaction callbacks as LOCAL_COMPLETED (bogdan)
  */
 
 #include <string.h>
@@ -148,7 +150,8 @@ static inline int check_params(str* method, str* to, str* from, dlg_t** dialog)
 /*
  * Send a request using data from the dialog structure
  */
-int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp)
+int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
+												transaction_cb cb, void* cbp)
 {
 	struct socket_info* send_sock;
 	union sockaddr_union to_su;
@@ -180,13 +183,15 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb
 		goto error2;
 	}
 
-	new_cell->completion_cb = cb;
-	new_cell->cbp = cbp;
-	
-	     /* cbp is installed -- tell error handling bellow not to free it */
-	cbp = 0;
+	/* add the callback the the transaction for LOCAL_COMPLETED event */
+	if (insert_tmcb( &(new_cell->tmcb_hl), TMCB_LOCAL_COMPLETED, cb, cbp)!=1) {
+		ret=E_OUT_OF_MEM;
+		LOG(L_ERR, "t_uac: short of tmcb shmem\n");
+		goto error2;
+	}
 
-	new_cell->is_invite = method->len == INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN) == 0;
+	new_cell->is_invite =
+		method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0;
 	new_cell->local= 1;
 	set_kr(REQ_FWDED);
 	
@@ -196,12 +201,13 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb
 	request->dst.proto = send_sock->proto;
 	request->dst.proto_reserved1 = 0;
 
-	     /* need to put in table to calculate label which is needed for printing */
+	/* need to put in table to calculate label which is needed for printing */
 	LOCK_HASH(new_cell->hash_index);
 	insert_into_hash_table_unsafe(new_cell);
 	UNLOCK_HASH(new_cell->hash_index);
 
-	buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len, send_sock);
+	buf = build_uac_req(method, headers, body, dialog, 0, new_cell,
+		&buf_len, send_sock);
 	if (!buf) {
 		LOG(L_ERR, "t_uac: Error while building message\n");
 		ret=E_OUT_OF_MEM;
@@ -217,23 +223,19 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb
 	
 	if (SEND_BUFFER(request) == -1) {
 		LOG(L_ERR, "t_uac: Attempt to send to '%.*s' failed\n", 
-		    dialog->hooks.next_hop->len,
-		    dialog->hooks.next_hop->s
-		    );
+			dialog->hooks.next_hop->len,
+			dialog->hooks.next_hop->s);
 	}
 	
 	start_retr(request);
 	return 1;
 
- error1:
+error1:
 	LOCK_HASH(new_cell->hash_index);
 	remove_from_hash_table_unsafe(new_cell);
 	UNLOCK_HASH(new_cell->hash_index);
 	free_cell(new_cell);
-
- error2:
-	     /* if we did not install cbp, release it now */
-	if (cbp) shm_free(cbp);
+error2:
 	return ret;
 }
 

+ 50 - 20
modules/tm/uac_fifo.c

@@ -1,5 +1,32 @@
 /*
  * $Id$
+ *
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ *  2003-12-03 : fifo_callback() updated for changes in tm callbacks (bogdan)
  */
 
 #include <string.h>
@@ -31,8 +58,8 @@ struct cb_data {
 
 
 struct str_list {
-        str s;
-        struct str_list *next;
+	str s;
+	struct str_list *next;
 };
 
 
@@ -502,8 +529,7 @@ static inline int print_uris(FILE* out, struct sip_msg* reply)
 }
 
 
-static void fifo_callback(struct cell *t, struct sip_msg *reply,
-			  int code, void *param)
+static void fifo_callback( struct cell *t, int type, struct tmcb_params *ps )
 {
 	
 	char *filename;
@@ -512,35 +538,39 @@ static void fifo_callback(struct cell *t, struct sip_msg *reply,
 
 	DBG("!!!!! ref_counter: %d\n", t->ref_count);
 
-	DBG("DEBUG: fifo UAC completed with status %d\n", code);
-	if (!t->cbp) {
-		LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", code);
+	DBG("DEBUG: fifo UAC completed with status %d\n", ps->code);
+	if (!ps->param) {
+		LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", ps->code);
 		return;
 	}
 
-	filename=(char *)(t->cbp);
-	if (reply==FAKED_REPLY) {
-		get_reply_status(&text,reply,code);
+	filename=(char *)(ps->param);
+	if (ps->rpl==FAKED_REPLY) {
+		get_reply_status( &text, ps->rpl, ps->code);
 		if (text.s==0) {
 			LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
-			fifo_reply(filename, "500 fifo_callback: get_reply_status failed\n");
-			return;
+			fifo_reply( filename,
+				"500 fifo_callback: get_reply_status failed\n");
+			goto done;
 		}
 		fifo_reply(filename, "%.*s\n", text.len, text.s );
 		pkg_free(text.s);
 	} else {
-		text.s=reply->first_line.u.reply.reason.s;
-		text.len=reply->first_line.u.reply.reason.len;
+		text.s = ps->rpl->first_line.u.reply.reason.s;
+		text.len = ps->rpl->first_line.u.reply.reason.len;
 
 		f = fopen(filename, "wt");
-		if (!f) return;
-		fprintf(f, "%d %.*s\n", reply->first_line.u.reply.statuscode, text.len, text.s);
-		print_uris(f, reply);
-		fprintf(f, "%s\n", reply->headers->name.s);
+		if (!f) goto done;
+		fprintf(f, "%d %.*s\n", ps->rpl->first_line.u.reply.statuscode,
+			text.len, text.s);
+		print_uris(f, ps->rpl);
+		fprintf(f, "%s\n", ps->rpl->headers->name.s);
 		fclose(f);
 	}
 	DBG("DEBUG: fifo_callback sucesssfuly completed\n");
-}	
+done:
+	shm_free(ps->param);
+}
 
 
 int fifo_uac(FILE *stream, char *response_file)
@@ -624,7 +654,7 @@ int fifo_uac(FILE *stream, char *response_file)
 
 	if (ret <= 0) {
 		err_ret = err2reason_phrase(ret, &sip_error, err_buf,
-					    sizeof(err_buf), "FIFO/UAC") ;
+			sizeof(err_buf), "FIFO/UAC") ;
 		if (err_ret > 0 )
 		{
 			fifo_uac_error(response_file, sip_error, err_buf);