Browse Source

- tm on_send callbacks support: if such a callback is registered it will be
called after tm sends a message. The callback can "see" what exactly was sent
on the wire and to whom. These callbacks are intended to be read-only
(no changes to the message are allowed). Their man purpose is extra-accounting
or logging. For more info see the comments in tm/t_hooks.h.

Andrei Pelinescu-Onciul 18 years ago
parent
commit
9217a64020
9 changed files with 231 additions and 32 deletions
  1. 9 1
      NEWS
  2. 5 2
      modules/tm/h_table.h
  3. 9 2
      modules/tm/t_cancel.c
  4. 11 1
      modules/tm/t_fwd.c
  5. 71 15
      modules/tm/t_hooks.c
  6. 80 2
      modules/tm/t_hooks.h
  7. 35 9
      modules/tm/t_reply.c
  8. 5 0
      modules/tm/timer.c
  9. 6 0
      modules/tm/uac.c

+ 9 - 1
NEWS

@@ -3,7 +3,15 @@ Release notes for SIP Express Router (ser)
 
 
 $Id$
 $Id$
 
 
-0.10.99-dev changes
+
+2.1.0 changes
+
+modules:
+ - tm        - new onsend callbacks support (require defining TMCB_ONSEND prior
+               to compiling tm)
+
+
+2.0.0 changes
 
 
 
 
 new archs:
 new archs:

+ 5 - 2
modules/tm/h_table.h

@@ -45,8 +45,10 @@
 #ifndef _H_TABLE_H
 #ifndef _H_TABLE_H
 #define _H_TABLE_H
 #define _H_TABLE_H
 
 
-#include <stdio.h>
-#include <stdlib.h>
+/*
+ #include <stdio.h>
+ #include <stdlib.h>
+*/
 
 
 #include "../../parser/msg_parser.h"
 #include "../../parser/msg_parser.h"
 #include "../../types.h"
 #include "../../types.h"
@@ -80,6 +82,7 @@ void unlock_hash(int i);
 #define NO_CANCEL       ( (char*) 0 )
 #define NO_CANCEL       ( (char*) 0 )
 #define EXTERNAL_CANCEL ( (char*) -1)
 #define EXTERNAL_CANCEL ( (char*) -1)
 
 
+#define TYPE_LOCAL_ACK    -2
 #define TYPE_LOCAL_CANCEL -1
 #define TYPE_LOCAL_CANCEL -1
 #define TYPE_REQUEST       0
 #define TYPE_REQUEST       0
 
 

+ 9 - 2
modules/tm/t_cancel.c

@@ -32,6 +32,7 @@
  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
  * 2004-02-13  timer_link.payload removed (bogdan)
  * 2004-02-13  timer_link.payload removed (bogdan)
  * 2006-10-10  cancel_uacs  & cancel_branch take more options now (andrei)
  * 2006-10-10  cancel_uacs  & cancel_branch take more options now (andrei)
+ * 2007-03-15  TMCB_ONSEND hooks added (andrei)
  */
  */
 
 
 #include <stdio.h> /* for FILE* in fifo_uac_cancel */
 #include <stdio.h> /* for FILE* in fifo_uac_cancel */
@@ -46,6 +47,7 @@
 #include "t_cancel.h"
 #include "t_cancel.h"
 #include "t_msgbuilder.h"
 #include "t_msgbuilder.h"
 #include "t_lookup.h" /* for t_lookup_callid in fifo_uac_cancel */
 #include "t_lookup.h" /* for t_lookup_callid in fifo_uac_cancel */
+#include "t_hooks.h"
 
 
 
 
 /* determine which branches should be canceled; do it
 /* determine which branches should be canceled; do it
@@ -114,9 +116,9 @@ int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
  *         -1 - error
  *         -1 - error
  * WARNING:
  * WARNING:
  *          - F_CANCEL_KILL_B should be used only if the transaction is killed
  *          - F_CANCEL_KILL_B should be used only if the transaction is killed
- *            explicitely afterwards (since it might kill all the timers
+ *            explicitly afterwards (since it might kill all the timers
  *            the transaction won't be able to "kill" itself => if not
  *            the transaction won't be able to "kill" itself => if not
- *            explicitely "put_on_wait" it migh leave forever)
+ *            explicitly "put_on_wait" it might live forever)
  *          - F_CANCEL_B_FAKE_REPLY must be used only if the REPLY_LOCK is not
  *          - F_CANCEL_B_FAKE_REPLY must be used only if the REPLY_LOCK is not
  *            held
  *            held
  */
  */
@@ -189,7 +191,12 @@ int cancel_branch( struct cell *t, int branch, int flags )
 	crb->activ_type = TYPE_LOCAL_CANCEL;
 	crb->activ_type = TYPE_LOCAL_CANCEL;
 
 
 	DBG("DEBUG: cancel_branch: sending cancel...\n");
 	DBG("DEBUG: cancel_branch: sending cancel...\n");
+#ifdef TMCB_ONSEND
+	if (SEND_BUFFER( crb )>=0)
+		run_onsend_callbacks(TMCB_REQUEST_SENT, crb, 0);
+#else
 	SEND_BUFFER( crb );
 	SEND_BUFFER( crb );
+#endif
 	/*sets and starts the FINAL RESPONSE timer */
 	/*sets and starts the FINAL RESPONSE timer */
 	if (start_retr( crb )!=0)
 	if (start_retr( crb )!=0)
 		LOG(L_CRIT, "BUG: cancel_branch: failed to start retransmission"
 		LOG(L_CRIT, "BUG: cancel_branch: failed to start retransmission"

+ 11 - 1
modules/tm/t_fwd.c

@@ -63,6 +63,7 @@
  *              stop retr. timers fix on cancel for non-invites     (andrei)
  *              stop retr. timers fix on cancel for non-invites     (andrei)
  *  2006-11-20  new_uri is no longer saved/restore across add_uac calls, since
  *  2006-11-20  new_uri is no longer saved/restore across add_uac calls, since
  *              print_uac_request is now uri safe (andrei)
  *              print_uac_request is now uri safe (andrei)
+ * 2007-03-15  TMCB_ONSEND hooks added (andrei)
  */
  */
 
 
 #include "defs.h"
 #include "defs.h"
@@ -507,6 +508,12 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 				if (SEND_BUFFER(&t_cancel->uac[i].request) == -1) {
 				if (SEND_BUFFER(&t_cancel->uac[i].request) == -1) {
 					LOG(L_ERR, "ERROR: e2e_cancel: send failed\n");
 					LOG(L_ERR, "ERROR: e2e_cancel: send failed\n");
 				}
 				}
+#ifdef TMCB_ONSEND
+				else{
+					run_onsend_callbacks(TMCB_REQUEST_SENT, 
+											&t_cancel->uac[i].request, 0);
+				}
+#endif
 				if (start_retr( &t_cancel->uac[i].request )!=0)
 				if (start_retr( &t_cancel->uac[i].request )!=0)
 					LOG(L_CRIT, "BUG: e2e_cancel: failed to start retr."
 					LOG(L_CRIT, "BUG: e2e_cancel: failed to start retr."
 							" for %p\n", &t_cancel->uac[i].request);
 							" for %p\n", &t_cancel->uac[i].request);
@@ -655,7 +662,7 @@ int t_send_branch( struct cell *t, int branch, struct sip_msg* p_msg ,
 	if (SEND_BUFFER( &uac->request)==-1) {
 	if (SEND_BUFFER( &uac->request)==-1) {
 		/* disable the current branch: set a "fake" timeout
 		/* disable the current branch: set a "fake" timeout
 		 *  reply code but don't set uac->reply, to avoid overriding 
 		 *  reply code but don't set uac->reply, to avoid overriding 
-		 *  a higly unlikely, perfectly timed fake reply (to a message
+		 *  a highly unlikely, perfectly timed fake reply (to a message
 		 *  we never sent).
 		 *  we never sent).
 		 * (code=final reply && reply==0 => t_pick_branch won't ever pick it)*/
 		 * (code=final reply && reply==0 => t_pick_branch won't ever pick it)*/
 		uac->last_received=408;
 		uac->last_received=408;
@@ -685,6 +692,9 @@ int t_send_branch( struct cell *t, int branch, struct sip_msg* p_msg ,
 		if (proxy) { proxy->errors++; proxy->ok=0; }
 		if (proxy) { proxy->errors++; proxy->ok=0; }
 		return -2;
 		return -2;
 	} else {
 	} else {
+#ifdef TMCB_ONSEND
+		run_onsend_callbacks(TMCB_REQUEST_SENT, &uac->request, 0);
+#endif
 		/* start retr. only if the send succeeded */
 		/* start retr. only if the send succeeded */
 		if (start_retr( &uac->request )!=0){
 		if (start_retr( &uac->request )!=0){
 			LOG(L_CRIT, "BUG: t_send_branch: retr. already started for %p\n",
 			LOG(L_CRIT, "BUG: t_send_branch: retr. already started for %p\n",

+ 71 - 15
modules/tm/t_hooks.c

@@ -34,6 +34,7 @@
  *  2004-08-23  user avp(attribute value pair) added -> making avp list
  *  2004-08-23  user avp(attribute value pair) added -> making avp list
  *              available in callbacks (bogdan)
  *              available in callbacks (bogdan)
  * 2007-03-08  membar_write() used in insert_tmcb(...) (andrei)
  * 2007-03-08  membar_write() used in insert_tmcb(...) (andrei)
+ * 2007-03-14  added *_SENT callbacks (andrei)
  */
  */
 
 
 #include "defs.h"
 #include "defs.h"
@@ -182,20 +183,12 @@ int register_tmcb( struct sip_msg* p_msg, struct cell *t, int types,
 }
 }
 
 
 
 
-void run_trans_callbacks( int type , struct cell *trans,
-						struct sip_msg *req, struct sip_msg *rpl, int code )
+static void run_trans_callbacks_internal(int type, struct cell *trans, 
+											struct tmcb_params *params)
 {
 {
-	static struct tmcb_params params = {0,0,0,0};
 	struct tm_callback    *cbp;
 	struct tm_callback    *cbp;
 	avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to;
 	avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to;
 
 
-	params.req = req;
-	params.rpl = rpl;
-	params.code = code;
-
-	if (trans->tmcb_hl.first==0 || ((trans->tmcb_hl.reg_types)&type)==0 )
-		return;
-
 	backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, &trans->uri_avps_from );
 	backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, &trans->uri_avps_from );
 	backup_uri_to = set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, &trans->uri_avps_to );
 	backup_uri_to = set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, &trans->uri_avps_to );
 	backup_from = set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, &trans->user_avps_from );
 	backup_from = set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, &trans->user_avps_from );
@@ -206,8 +199,8 @@ void run_trans_callbacks( int type , struct cell *trans,
 		if ( (cbp->types)&type ) {
 		if ( (cbp->types)&type ) {
 			DBG("DBG: trans=%p, callback type %d, id %d entered\n",
 			DBG("DBG: trans=%p, callback type %d, id %d entered\n",
 				trans, type, cbp->id );
 				trans, type, cbp->id );
-			params.param = &(cbp->param);
-			cbp->callback( trans, type, &params );
+			params->param = &(cbp->param);
+			cbp->callback( trans, type, params );
 		}
 		}
 	}
 	}
 	set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, backup_dom_to );
 	set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, backup_dom_to );
@@ -220,17 +213,80 @@ void run_trans_callbacks( int type , struct cell *trans,
 
 
 
 
 
 
+void run_trans_callbacks( int type , struct cell *trans,
+						struct sip_msg *req, struct sip_msg *rpl, int code )
+{
+	struct tmcb_params params;
+	if (trans->tmcb_hl.first==0 || ((trans->tmcb_hl.reg_types)&type)==0 )
+		return;
+	memset (&params, 0, sizeof(params));
+	params.req = req;
+	params.rpl = rpl;
+	params.code = code;
+	run_trans_callbacks_internal(type, trans, &params);
+}
+
+
+
+#ifdef TMCB_ONSEND
+void run_onsend_callbacks(int type, struct retr_buf* rbuf, int retr)
+{
+	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;
+	memset (&params, 0, sizeof(params));
+	params.send_buf.s=rbuf->buffer;
+	params.send_buf.len=rbuf->buffer_len;
+	params.dst=&rbuf->dst;
+	params.is_retr=retr;
+	params.branch=rbuf->branch;
+	params.t_rbuf=rbuf;
+	params.code=rbuf->activ_type;
+	/* req, rpl */
+	run_trans_callbacks_internal(type, trans, &params);
+}
+
+
+void run_onsend_callbacks2(int type , struct retr_buf* rbuf, char* buf,
+							int buf_len, struct dest_info* dst, int code)
+{
+	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;
+	memset (&params, 0, sizeof(params));
+	params.send_buf.s=buf;
+	params.send_buf.len=buf_len;
+	params.dst=dst;
+	params.is_retr=0;
+	params.branch=rbuf->branch;
+	params.t_rbuf=rbuf;
+	params.code=code;
+	/* req, rpl */
+	run_trans_callbacks_internal(type, trans, &params);
+}
+
+#endif
+
 void run_reqin_callbacks( struct cell *trans, struct sip_msg *req, int code )
 void run_reqin_callbacks( struct cell *trans, struct sip_msg *req, int code )
 {
 {
-	static struct tmcb_params params = {0,0,0,0};
+	static struct tmcb_params params;
 	struct tm_callback    *cbp;
 	struct tm_callback    *cbp;
 	avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to;
 	avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to;
 
 
+	if (req_in_tmcb_hl->first==0)
+		return;
+	memset (&params, 0, sizeof(params));
 	params.req = req;
 	params.req = req;
 	params.code = code;
 	params.code = code;
 
 
-	if (req_in_tmcb_hl->first==0)
-		return;
 
 
 	backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, &trans->uri_avps_from );
 	backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, &trans->uri_avps_from );
 	backup_uri_to = set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, &trans->uri_avps_to );
 	backup_uri_to = set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, &trans->uri_avps_to );

+ 80 - 2
modules/tm/t_hooks.h

@@ -31,6 +31,7 @@
  * 2003-12-04 : global callbacks moved into transaction callbacks;
  * 2003-12-04 : global callbacks moved into transaction callbacks;
  *              multiple events per callback added; single list per
  *              multiple events per callback added; single list per
  *              transaction for all its callbacks (bogdan)
  *              transaction for all its callbacks (bogdan)
+ * 2007-03-14   added *_SENT callbacks (andrei)
  */
  */
 
 
 
 
@@ -39,6 +40,15 @@
 
 
 #include "defs.h"
 #include "defs.h"
 
 
+/* if defined support for ONSEND callbacks will be added and
+ * the tmcb_params structure will get some additional members */
+/*
+#define TMCB_ONSEND
+*/
+#ifdef TMCB_ONSEND
+#include "../../ip_addr.h" /* dest_info */
+#endif
+
 struct sip_msg;
 struct sip_msg;
 struct cell;
 struct cell;
 
 
@@ -52,7 +62,13 @@ struct cell;
 #define TMCB_RESPONSE_OUT_N     7
 #define TMCB_RESPONSE_OUT_N     7
 #define TMCB_LOCAL_COMPLETED_N  8
 #define TMCB_LOCAL_COMPLETED_N  8
 #define TMCB_LOCAL_RESPONSE_OUT_N 9
 #define TMCB_LOCAL_RESPONSE_OUT_N 9
+#ifdef TMCB_ONSEND
+#define TMCB_REQUEST_SENT_N     10
+#define TMCB_RESPONSE_SENT_N    11
+#define TMCB_MAX_N              11
+#else
 #define TMCB_MAX_N              9
 #define TMCB_MAX_N              9
+#endif
 
 
 #define TMCB_REQUEST_IN       (1<<TMCB_REQUEST_IN_N)
 #define TMCB_REQUEST_IN       (1<<TMCB_REQUEST_IN_N)
 #define TMCB_RESPONSE_IN      (1<<TMCB_RESPONSE_IN_N)
 #define TMCB_RESPONSE_IN      (1<<TMCB_RESPONSE_IN_N)
@@ -64,6 +80,10 @@ struct cell;
 #define TMCB_RESPONSE_OUT     (1<<TMCB_RESPONSE_OUT_N)
 #define TMCB_RESPONSE_OUT     (1<<TMCB_RESPONSE_OUT_N)
 #define TMCB_LOCAL_COMPLETED  (1<<TMCB_LOCAL_COMPLETED_N)
 #define TMCB_LOCAL_COMPLETED  (1<<TMCB_LOCAL_COMPLETED_N)
 #define TMCB_LOCAL_RESPONSE_OUT (1<<TMCB_LOCAL_RESPONSE_OUT_N)
 #define TMCB_LOCAL_RESPONSE_OUT (1<<TMCB_LOCAL_RESPONSE_OUT_N)
+#ifdef TMCB_ONSEND
+#define TMCB_REQUEST_SENT      (1<<TMCB_REQUEST_SENT_N)
+#define TMCB_RESPONSE_SENT     (1<<TMCB_RESPONSE_SENT_N)
+#endif
 #define TMCB_MAX              ((1<<(TMCB_MAX_N+1))-1)
 #define TMCB_MAX              ((1<<(TMCB_MAX_N+1))-1)
 
 
 
 
@@ -199,11 +219,49 @@ struct cell;
  *  called multiple time quasi-simultaneously. No lock is held.
  *  called multiple time quasi-simultaneously. No lock is held.
  *  It's unsafe to register other TMCB callbacks.
  *  It's unsafe to register other TMCB callbacks.
  *
  *
+ *  TMCB_ONSEND callbacks
+ *
+ *  All of the following callbacks are called immediately after or before 
+ *  sending a message. All of them are read-only (no change can be made to
+ * the message). These callbacks use the t_rbuf, send_buf, dst, is_retr
+ *  and the code members of the tmcb_params structure.
+ *  For a request code is <=0. code values can be TYPE_LOCAL_ACK for an ACK 
+ *  generated by ser, TYPE_LOCAL_CANCEL for a CANCEL generated by ser 
+ *  and TYPE_REQUEST for all the other requests or requests generated via 
+ *  t_uac.
+ *   For a reply the code is the response status (which is always >0, e.g. 200,
+ *   408, a.s.o).
+ *  Note: - these callbacks can be used only if TMCB_ONSEND is defined.
+ *        - the callbacks will be called sometimes with the REPLY lock held
+ *          and sometimes without it, so trying to acquire the REPLY lock
+ *          from these callbacks could lead to deadlocks (avoid it unless
+ *           you really know what you're doing).
+ *
+ *  TMCB_REQUEST_SENT (present only if TMCB_ONSEND is defined) -- called 
+ *  each time a request was sent (even for retransmissions), it includes 
+ *  local and forwarded request, ser generated CANCELs and ACKs. The 
+ *  tmcb_params structure will have the t_rbuf, dst, send_buf and is_retr
+ *  members  filled.
+ *  This callback is "read-only", the message was already sent and no changes
+ *  are allowed.
+ *  Note: send_buf can be different from t_rbuf->buffer for ACKs (in this
+ *   case t_rbuf->buf will contain the last request sent on the branch and
+ *   its destination). The same goes for t_rbuf->dst and tmcb->dst for local 
+ *   transactions ACKs to 2xxs.
+ *
+ *  TMCB_RESPONSE_SENT  (present only if TMCB_ONSEND is defined) -- called 
+ *  each time a response was sent (even for retransmissions). The tmcb_params
+ *   structure will have t_rbuf set to the reply retransmission buffer and
+ *   send_buf set to the data sent (in this case it will always be the same 
+ *   with t_rbuf->buf). is_retr will also be set if the reply is retransmitted
+ *   by ser.
+ *  This callback is "read-only", the message was already sent and no changes
+ *  are allowed.
  *
  *
 
 
 	the callback's param MUST be in shared memory and will
 	the callback's param MUST be in shared memory and will
 	NOT be freed by TM; you must do it yourself from the
 	NOT be freed by TM; you must do it yourself from the
-	callback function id necessary.
+	callback function if necessary.
 */
 */
 
 
 
 
@@ -211,8 +269,22 @@ struct cell;
 struct tmcb_params {
 struct tmcb_params {
 	struct sip_msg* req;
 	struct sip_msg* req;
 	struct sip_msg* rpl;
 	struct sip_msg* rpl;
-	int code;
 	void **param;
 	void **param;
+#ifdef TMCB_ONSEND
+	struct retr_buf* t_rbuf; /* transaction retr. buf., all the information
+								 regarding destination, data that is/was
+								 actually sent on the net, branch a.s.o is
+								 inside */
+	struct dest_info* dst; /* destination */
+	str send_buf; /* what was/will be sent on the net, used for ACKs
+					(which don't have a retr_buf). */
+	short is_retr; /* set if this is a _ser_ retransmission (but not if
+					 if it's a "forwarded" retr., like a retr. 200 Ok for 
+					 example) */
+	unsigned short branch;
+	/* could also be: send_buf, dst, branch */
+#endif
+	int code;
 };
 };
 
 
 /* callback function prototype */
 /* callback function prototype */
@@ -267,4 +339,10 @@ void run_trans_callbacks( int type , struct cell *trans,
 /* run all REQUEST_IN callbacks */
 /* run all REQUEST_IN callbacks */
 void run_reqin_callbacks( struct cell *trans, struct sip_msg *req, int code );
 void run_reqin_callbacks( struct cell *trans, struct sip_msg *req, int code );
 
 
+#ifdef TMCB_ONSEND
+void run_onsend_callbacks(int type, struct retr_buf* rbuf, int retr);
+void run_onsend_callbacks2(int type , struct retr_buf* rbuf, char* buf,
+							int buf_len, struct dest_info* dst, int code);
+#endif
+
 #endif
 #endif

+ 35 - 9
modules/tm/t_reply.c

@@ -80,7 +80,8 @@
  *               the final response is 401 or 407 (andrei)
  *               the final response is 401 or 407 (andrei)
  * 2007-03-08  membar_write() used in update_totag_set(...)(andrei)
  * 2007-03-08  membar_write() used in update_totag_set(...)(andrei)
  * 2007-03-15  build_local_ack: removed next_hop and replaced with dst to 
  * 2007-03-15  build_local_ack: removed next_hop and replaced with dst to 
- *              avoid resolving next_hop twice (andrei)
+ *              avoid resolving next_hop twice
+*              added TMCB_ONSEND callbacks support for replies & ACKs (andrei)
  *
  *
  */
  */
 
 
@@ -491,7 +492,13 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len,
 	if (!trans->uas.response.dst.send_sock) {
 	if (!trans->uas.response.dst.send_sock) {
 		LOG(L_ERR, "ERROR: _reply_light: no resolved dst to send reply to\n");
 		LOG(L_ERR, "ERROR: _reply_light: no resolved dst to send reply to\n");
 	} else {
 	} else {
+#ifdef TMCB_ONSEND
+		if (SEND_PR_BUFFER( rb, buf, len )>=0)
+			run_onsend_callbacks2(TMCB_RESPONSE_SENT, rb, buf, len, &rb->dst,
+									code);
+#else
 		SEND_PR_BUFFER( rb, buf, len );
 		SEND_PR_BUFFER( rb, buf, len );
+#endif
 		DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n",
 		DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n",
 			buf, buf, rb->buffer, rb->buffer );
 			buf, buf, rb->buffer, rb->buffer );
 	}
 	}
@@ -1069,6 +1076,9 @@ int t_retransmit_reply( struct cell *t )
 	memcpy( b, t->uas.response.buffer, len );
 	memcpy( b, t->uas.response.buffer, len );
 	UNLOCK_REPLIES( t );
 	UNLOCK_REPLIES( t );
 	SEND_PR_BUFFER( & t->uas.response, b, len );
 	SEND_PR_BUFFER( & t->uas.response, b, len );
+#ifdef TMCB_ONSEND
+	run_onsend_callbacks(TMCB_RESPONSE_SENT, &t->uas.response, 1);
+#endif
 	DBG("DEBUG: reply retransmitted. buf=%p: %.9s..., shmem=%p: %.9s\n",
 	DBG("DEBUG: reply retransmitted. buf=%p: %.9s..., shmem=%p: %.9s\n",
 		b, b, t->uas.response.buffer, t->uas.response.buffer );
 		b, b, t->uas.response.buffer, t->uas.response.buffer );
 	return 1;
 	return 1;
@@ -1431,12 +1441,15 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
 
 
 	/* send it now (from the private buffer) */
 	/* send it now (from the private buffer) */
 	if (relay >= 0) {
 	if (relay >= 0) {
-		SEND_PR_BUFFER( uas_rb, buf, res_len );
-		DBG("DEBUG: reply relayed. buf=%p: %.15s..., shmem=%p: %.9s totag_retr=%d\n",
-			buf, buf, uas_rb->buffer, uas_rb->buffer, totag_retr );
-		if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) {
-			run_trans_callbacks( TMCB_RESPONSE_OUT, t, t->uas.request,
-				relayed_msg, relayed_code);
+		if (SEND_PR_BUFFER( uas_rb, buf, res_len )>=0){
+			if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) {
+				run_trans_callbacks( TMCB_RESPONSE_OUT, t, t->uas.request,
+					relayed_msg, relayed_code);
+			}
+#ifdef TMCB_ONSEND
+			run_onsend_callbacks2(TMCB_RESPONSE_SENT, uas_rb, buf, res_len,
+									&uas_rb->dst, relayed_code);
+#endif
 		}
 		}
 		pkg_free( buf );
 		pkg_free( buf );
 	}
 	}
@@ -1615,15 +1628,28 @@ int reply_received( struct sip_msg  *p_msg )
 			if (msg_status >= 300) {
 			if (msg_status >= 300) {
 				ack = build_ack(p_msg, t, branch, &ack_len);
 				ack = build_ack(p_msg, t, branch, &ack_len);
 				if (ack) {
 				if (ack) {
+#ifdef	TMCB_ONSEND
+					if (SEND_PR_BUFFER(&uac->request, ack, ack_len)>=0)
+						run_onsend_callbacks2(TMCB_REQUEST_SENT,
+									&uac->request, ack, ack_len, 
+									&uac->request.dst,
+									TYPE_LOCAL_ACK);
+#else
 					SEND_PR_BUFFER(&uac->request, ack, ack_len);
 					SEND_PR_BUFFER(&uac->request, ack, ack_len);
+#endif
 					shm_free(ack);
 					shm_free(ack);
 				}
 				}
 			} else if (is_local(t) /*&& 200 <= msg_status < 300*/) {
 			} else if (is_local(t) /*&& 200 <= msg_status < 300*/) {
 				ack = build_local_ack(p_msg, t, branch, &ack_len, &lack_dst);
 				ack = build_local_ack(p_msg, t, branch, &ack_len, &lack_dst);
 				if (ack) {
 				if (ack) {
-					if (msg_send(&lack_dst, ack, ack_len)<0){
+					if (msg_send(&lack_dst, ack, ack_len)<0)
 						LOG(L_ERR, "Error while sending local ACK\n");
 						LOG(L_ERR, "Error while sending local ACK\n");
-					}
+#ifdef	TMCB_ONSEND
+					else
+						run_onsend_callbacks2(TMCB_REQUEST_SENT,
+									&uac->request, ack, ack_len, &lack_dst,
+									TYPE_LOCAL_ACK);
+#endif
 					shm_free(ack);
 					shm_free(ack);
 				}
 				}
 			}
 			}

+ 5 - 0
modules/tm/timer.c

@@ -107,6 +107,7 @@
  *               return a 408
  *               return a 408
  *              set the corresponding "faked" failure route sip_msg->msg_flags 
  *              set the corresponding "faked" failure route sip_msg->msg_flags 
  *               on timeout or if the branch received a reply (andrei)
  *               on timeout or if the branch received a reply (andrei)
+ *  2007-03-15  TMCB_ONSEND callbacks support (andrei)
  */
  */
 
 
 #include "defs.h"
 #include "defs.h"
@@ -129,6 +130,7 @@
 #include "t_funcs.h"
 #include "t_funcs.h"
 #include "t_reply.h"
 #include "t_reply.h"
 #include "t_cancel.h"
 #include "t_cancel.h"
+#include "t_hooks.h"
 #ifdef USE_DNS_FAILOVER
 #ifdef USE_DNS_FAILOVER
 #include "t_fwd.h" /* t_send_branch */
 #include "t_fwd.h" /* t_send_branch */
 #endif
 #endif
@@ -305,6 +307,9 @@ inline static ticks_t retransmission_handler( struct retr_buf *r_buf )
 				fake_reply(r_buf->my_T, r_buf->branch, 503 );
 				fake_reply(r_buf->my_T, r_buf->branch, 503 );
 				return (ticks_t)-1;
 				return (ticks_t)-1;
 			}
 			}
+#ifdef TMCB_ONSEND
+			run_onsend_callbacks(TMCB_REQUEST_SENT, r_buf, 1);
+#endif
 	} else {
 	} else {
 #ifdef EXTRA_DEBUG
 #ifdef EXTRA_DEBUG
 			DBG("DEBUG: retransmission_handler : "
 			DBG("DEBUG: retransmission_handler : "

+ 6 - 0
modules/tm/uac.c

@@ -53,6 +53,7 @@
  *  2005-12-16  t_uac will set the new_cell timers to the default values,
  *  2005-12-16  t_uac will set the new_cell timers to the default values,
  *               fixes 0 fr_timer bug (andrei)
  *               fixes 0 fr_timer bug (andrei)
  *  2006-08-11  t_uac uses dns failover until it finds a send socket (andrei)
  *  2006-08-11  t_uac uses dns failover until it finds a send socket (andrei)
+ *  2007-03-15  TMCB_ONSEND callbacks support added (andrei)
  */
  */
 
 
 #include <string.h>
 #include <string.h>
@@ -344,6 +345,11 @@ static inline void send_prepared_request_impl(struct retr_buf *request, int retr
 	if (SEND_BUFFER(request) == -1) {
 	if (SEND_BUFFER(request) == -1) {
 		LOG(L_ERR, "t_uac: Attempt to send to precreated request failed\n");
 		LOG(L_ERR, "t_uac: Attempt to send to precreated request failed\n");
 	}
 	}
+#ifdef TMCB_ONSEND
+	else
+		/* we don't know the method here */
+		run_onsend_callbacks(TMCB_REQUEST_SENT, request, 0);
+#endif
 	
 	
 	if (retransmit && (start_retr(request)!=0))
 	if (retransmit && (start_retr(request)!=0))
 		LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", request);
 		LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", request);