Răsfoiți Sursa

Function t_uac splitted into two parts - one which prepares the message and one
which sends it. Both are accessible for requests within dialogs through
tm_binds structure (prepare_request_within, send_prepared_request).

This is needed to allow sending in-dialog messages outside of critical section
(VERY useful for TCP transport when used nonzero TCP timeouts - in that case
may be the critical section locked for seconds!).

Vaclav Kubart 19 ani în urmă
părinte
comite
2410e6eb24
4 a modificat fișierele cu 85 adăugiri și 20 ștergeri
  1. 3 1
      modules/tm/tm_load.c
  2. 2 0
      modules/tm/tm_load.h
  3. 70 19
      modules/tm/uac.c
  4. 10 0
      modules/tm/uac.h

+ 3 - 1
modules/tm/tm_load.c

@@ -158,7 +158,9 @@ int load_tm( struct tm_binds *tmb)
 		LOG( L_ERR, LOAD_ERROR "'t_uac' not found\n");
 		return -1;
 	}
-
+	tmb->prepare_request_within = prepare_req_within;
+	tmb->send_prepared_request = send_prepared_request;
+	
 	tmb->route_mode = &rmode;
 	return 1;
 }

+ 2 - 0
modules/tm/tm_load.h

@@ -100,6 +100,8 @@ struct tm_binds {
 	tgett_f            t_gett;
 	calculate_hooks_f  calculate_hooks;
 	t_uac_t            t_uac;
+	prepare_request_within_f  prepare_request_within;
+	send_prepared_request_f   send_prepared_request;
 	enum route_mode*   route_mode;
 };
 

+ 70 - 19
modules/tm/uac.c

@@ -164,11 +164,8 @@ static inline unsigned int dlg2hash( dlg_t* dlg )
 	return hashid;
 }
 
-/*
- * 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)
+static inline int t_uac_prepare(str* method, str* headers, str* body, dlg_t* dialog,
+	  transaction_cb cb, void* cbp, struct retr_buf **dst_req)
 {
 	struct dest_info dst;
 	struct cell *new_cell;
@@ -178,6 +175,7 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
 	unsigned int hi;
 
 	ret=-1;
+	/*if (dst_req) *dst_req = NULL;*/
 	
 	/*** added by dcm 
 	 * - needed by external ua to send a request within a dlg
@@ -216,12 +214,12 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
 
 	/* add the callback the the transaction for LOCAL_COMPLETED event */
  
-        flags = TMCB_LOCAL_COMPLETED;
-             /* Add also TMCB_LOCAL_REPLY_OUT if provisional replies are desired */
-        if (pass_provisional_replies) flags |= TMCB_LOCAL_RESPONSE_OUT;
- 
-        if(cb && insert_tmcb(&(new_cell->tmcb_hl), flags, cb, cbp)!=1){
-                ret=E_OUT_OF_MEM; 
+	flags = TMCB_LOCAL_COMPLETED;
+	/* Add also TMCB_LOCAL_REPLY_OUT if provisional replies are desired */
+	if (pass_provisional_replies) flags |= TMCB_LOCAL_RESPONSE_OUT;
+
+	if(cb && insert_tmcb(&(new_cell->tmcb_hl), flags, cb, cbp)!=1){
+		ret=E_OUT_OF_MEM; 
 		LOG(L_ERR, "t_uac: short of tmcb shmem\n");
 		goto error2;
 	}
@@ -255,14 +253,7 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
 	request->buffer_len = buf_len;
 	new_cell->nr_of_outgoings++;
 	
-	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);
-	}
-	
-	if (start_retr(request)!=0)
-		LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", request);
+	if (dst_req) *dst_req = request;
 	return 1;
 
  error1:
@@ -274,6 +265,66 @@ error2:
 	return ret;
 }
 
+/*
+ * Prepare a message within a dialog
+ */
+int prepare_req_within(str* method, str* headers, 
+		str* body, dlg_t* dialog, transaction_cb completion_cb, 
+		void* cbp, struct retr_buf **dst_req)
+{
+	if (!method || !dialog) {
+		LOG(L_ERR, "req_within: Invalid parameter value\n");
+		goto err;
+	}
+
+	if (dialog->state != DLG_CONFIRMED) {
+		LOG(L_ERR, "req_within: Dialog is not confirmed yet\n");
+		goto err;
+	}
+
+	if ((method->len == 3) && (!memcmp("ACK", method->s, 3))) goto send;
+	if ((method->len == 6) && (!memcmp("CANCEL", method->s, 6))) goto send;
+	dialog->loc_seq.value++; /* Increment CSeq */
+ send:
+	return t_uac_prepare(method, headers, body, dialog, completion_cb, cbp, dst_req);
+
+ err:
+	/* if (cbp) shm_free(cbp); */
+	/* !! never free cbp here because if t_uac_prepare fails, cbp is not freed
+	 * and thus caller has no chance to discover if it is freed or not !! */
+	return -1;
+}
+
+static inline void send_prepared_request_impl(struct retr_buf *request)
+{
+	if (SEND_BUFFER(request) == -1) {
+		LOG(L_ERR, "t_uac: Attempt to send to precreated request failed\n");
+	}
+	
+	if (start_retr(request)!=0)
+		LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", request);
+}
+
+void send_prepared_request(struct retr_buf *request)
+{
+	send_prepared_request_impl(request);
+}
+
+/*
+ * 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)
+{
+	struct retr_buf *request;
+	int ret;
+
+	ret = t_uac_prepare(method, headers, body, dialog, cb, cbp, &request);
+	if (ret < 0) return ret;
+	send_prepared_request_impl(request);
+	return ret;
+}
+
 
 /*
  * Send a message within a dialog

+ 10 - 0
modules/tm/uac.h

@@ -37,6 +37,7 @@
 #include "../../str.h"
 #include "dlg.h"
 #include "t_hooks.h"
+#include "h_table.h"
 
 #define DEFAULT_CSEQ 10 /* Default CSeq number */
 
@@ -50,6 +51,10 @@ typedef int (*reqwith_t)(str* m, str* h, str* b, dlg_t* d, transaction_cb c, voi
 typedef int (*reqout_t)(str* m, str* t, str* f, str* h, str* b, dlg_t** d, transaction_cb c, void* cp);
 typedef int (*req_t)(str* m, str* ruri, str* t, str* f, str* h, str* b, str *next_hop, transaction_cb c, void* cp);
 typedef int (*t_uac_t)(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp);
+typedef int (*prepare_request_within_f)(str* method, str* headers, 
+		str* body, dlg_t* dialog, transaction_cb cb, void* cbp,
+		struct retr_buf **request_dst);
+typedef void (*send_prepared_request_f)(struct retr_buf *request_dst);
 
 
 /*
@@ -86,5 +91,10 @@ int req_outside(str* m, str* t, str* f, str* h, str* b, dlg_t** d, transaction_c
  */
 int request(str* m, str* ruri, str* to, str* from, str* h, str* b, str *next_hop, transaction_cb c, void* cp);
 
+int prepare_req_within(str* method, str* headers, str* body, dlg_t* dialog,
+	  transaction_cb cb, void* cbp, struct retr_buf **dst_req);
+
+void send_prepared_request(struct retr_buf *request);
+
 
 #endif