Browse code

tm: implemented t_uac_wait_block rpc command

- it blocks while waiting for the reply to return the code and reason
text

Daniel-Constantin Mierla authored on 20/01/2021 07:11:45
Showing 3 changed files
... ...
@@ -23,17 +23,202 @@
23 23
 #include "../../core/ut.h"
24 24
 #include "../../core/parser/parse_from.h"
25 25
 #include "../../core/str_list.h"
26
+#include "../../core/timer_proc.h"
27
+#include "../../core/utils/sruid.h"
26 28
 #include "ut.h"
27 29
 #include "dlg.h"
28 30
 #include "uac.h"
29 31
 #include "callid.h"
30 32
 
31 33
 
32
-
33 34
 /* RPC substitution char (used in rpc_t_uac headers) */
34 35
 #define SUBST_CHAR '!'
35 36
 
37
+#define TM_RPC_RESPONSE_LIFETIME 300
38
+#define TM_RPC_RESPONSE_TIMERSTEP 10
39
+
40
+void tm_rpc_response_list_clean(unsigned int ticks, void *param);
41
+
42
+typedef struct tm_rpc_response {
43
+	str ruid;
44
+	int flags;
45
+	int rcode;
46
+	str rtext;
47
+	time_t rtime;
48
+	struct tm_rpc_response *next;
49
+} tm_rpc_response_t;
50
+
51
+typedef struct tm_rpc_response_list {
52
+	gen_lock_t rlock;
53
+	tm_rpc_response_t *rlist;
54
+} tm_rpc_response_list_t;
55
+
56
+static tm_rpc_response_list_t *_tm_rpc_response_list = NULL;
57
+
58
+static sruid_t _tm_rpc_sruid;
59
+
60
+/**
61
+ *
62
+ */
63
+int tm_rpc_response_list_init(void)
64
+{
65
+	if(_tm_rpc_response_list != NULL) {
66
+		return 0;
67
+	}
68
+	if(sruid_init(&_tm_rpc_sruid, '-', "tmrp", SRUID_INC)<0) {
69
+		LM_ERR("failed to init sruid\n");
70
+		return -1;
71
+	}
72
+	if(sr_wtimer_add(tm_rpc_response_list_clean, 0,
73
+				TM_RPC_RESPONSE_TIMERSTEP)<0) {
74
+		LM_ERR("failed to register timer routine\n");
75
+		return -1;
76
+	}
77
+	_tm_rpc_response_list = shm_malloc(sizeof(tm_rpc_response_list_t));
78
+	if(_tm_rpc_response_list == NULL) {
79
+		SHM_MEM_ERROR;
80
+		return -1;
81
+	}
82
+
83
+	memset(_tm_rpc_response_list, 0, sizeof(tm_rpc_response_list_t));
84
+
85
+	lock_init(&_tm_rpc_response_list->rlock);
36 86
 
87
+	return 0;
88
+}
89
+
90
+/**
91
+ *
92
+ */
93
+int tm_rpc_response_list_destroy(void)
94
+{
95
+	tm_rpc_response_t *rl0 = NULL;
96
+	tm_rpc_response_t *rl1 = NULL;
97
+
98
+	if(_tm_rpc_response_list == NULL) {
99
+		return 0;
100
+	}
101
+
102
+	rl1 = _tm_rpc_response_list->rlist;
103
+
104
+	while(rl1!=NULL) {
105
+		rl0 = rl1;
106
+		rl1 = rl1->next;
107
+		shm_free(rl0);
108
+	}
109
+	lock_destroy(&_tm_rpc_response_list->rlock);
110
+	shm_free(_tm_rpc_response_list);
111
+	_tm_rpc_response_list = NULL;
112
+
113
+	return 0;
114
+}
115
+
116
+/**
117
+ *
118
+ */
119
+int tm_rpc_response_list_add(str *ruid, int rcode, str *rtext)
120
+{
121
+	size_t rsize = 0;
122
+	tm_rpc_response_t *ri = NULL;
123
+	if(_tm_rpc_response_list == NULL) {
124
+		LM_ERR("rpc response list not initialized\n");
125
+		return -1;
126
+	}
127
+
128
+	rsize = sizeof(tm_rpc_response_t) + ruid->len + 2
129
+				+ ((rtext!=NULL)?rtext->len:0);
130
+
131
+	ri = (tm_rpc_response_t*)shm_malloc(rsize);
132
+	if(ri==NULL) {
133
+		SHM_MEM_ERROR;
134
+		return -1;
135
+	}
136
+	memset(ri, 0, rsize);
137
+
138
+	ri->ruid.s = (char*)ri + sizeof(tm_rpc_response_t);
139
+	ri->ruid.len = ruid->len;
140
+	memcpy(ri->ruid.s, ruid->s, ruid->len);
141
+	ri->rtime = time(NULL);
142
+	ri->rcode = rcode;
143
+	if(rtext!=NULL) {
144
+		ri->rtext.s = ri->ruid.s + ri->ruid.len + 1;
145
+		ri->rtext.len = rtext->len;
146
+		memcpy(ri->rtext.s, rtext->s, rtext->len);
147
+	}
148
+	lock_get(&_tm_rpc_response_list->rlock);
149
+	ri->next = _tm_rpc_response_list->rlist;
150
+	_tm_rpc_response_list->rlist = ri;
151
+	lock_release(&_tm_rpc_response_list->rlock);
152
+
153
+	return 0;
154
+}
155
+
156
+/**
157
+ *
158
+ */
159
+tm_rpc_response_t *tm_rpc_response_list_get(str *ruid)
160
+{
161
+	tm_rpc_response_t *ri0 = NULL;
162
+	tm_rpc_response_t *ri1 = NULL;
163
+
164
+	if(_tm_rpc_response_list == NULL) {
165
+		LM_ERR("rpc response list not initialized\n");
166
+		return NULL;
167
+	}
168
+
169
+	lock_get(&_tm_rpc_response_list->rlock);
170
+	ri1 = _tm_rpc_response_list->rlist;
171
+	while(ri1!=NULL) {
172
+		if(ri1->ruid.len==ruid->len
173
+				&& memcmp(ri1->ruid.s, ruid->s, ruid->len)==0) {
174
+			if(ri0 == NULL) {
175
+				_tm_rpc_response_list->rlist = ri1->next;
176
+			} else {
177
+				ri0->next = ri1->next;
178
+			}
179
+			lock_release(&_tm_rpc_response_list->rlock);
180
+			return ri1;
181
+		}
182
+		ri0 = ri1;
183
+		ri1 = ri1->next;
184
+	}
185
+	lock_release(&_tm_rpc_response_list->rlock);
186
+	return NULL;
187
+}
188
+
189
+/**
190
+ *
191
+ */
192
+void tm_rpc_response_list_clean(unsigned int ticks, void *param)
193
+{
194
+	tm_rpc_response_t *ri0 = NULL;
195
+	tm_rpc_response_t *ri1 = NULL;
196
+	time_t tnow;
197
+
198
+	if(_tm_rpc_response_list == NULL) {
199
+		return;
200
+	}
201
+
202
+	tnow = time(NULL);
203
+	lock_get(&_tm_rpc_response_list->rlock);
204
+	ri1 = _tm_rpc_response_list->rlist;
205
+	while(ri1!=NULL) {
206
+		if(ri1->rtime < tnow - TM_RPC_RESPONSE_LIFETIME) {
207
+			if(ri0 == NULL) {
208
+				_tm_rpc_response_list->rlist = ri1->next;
209
+			} else {
210
+				ri0->next = ri1->next;
211
+			}
212
+			LM_DBG("freeing item [%.*s]\n", ri1->ruid.len, ri1->ruid.s);
213
+			shm_free(ri1);
214
+			ri1 = ri0->next;
215
+		} else {
216
+			ri0 = ri1;
217
+			ri1 = ri1->next;
218
+		}
219
+	}
220
+	lock_release(&_tm_rpc_response_list->rlock);
221
+}
37 222
 
38 223
 /** make sure the rpc user created the msg properly.
39 224
  * Make sure that the FIFO user created the message
... ...
@@ -393,6 +578,25 @@ static void rpc_uac_callback(struct cell* t, int type, struct tmcb_params* ps)
393 578
 }
394 579
 
395 580
 
581
+/* t_uac callback */
582
+static void rpc_uac_block_callback(struct cell* t, int type,
583
+		struct tmcb_params* ps)
584
+{
585
+	str *ruid;
586
+	str rtext;
587
+
588
+	ruid = (str*)(*ps->param);
589
+	*ps->param=0;
590
+	if (ps->rpl==FAKED_REPLY) {
591
+		rtext.s = error_text(ps->code);
592
+		rtext.len = strlen(rtext.s);
593
+	} else {
594
+		rtext = ps->rpl->first_line.u.reply.reason;
595
+	}
596
+	tm_rpc_response_list_add(ruid, ps->code, &rtext);
597
+	shm_free(ruid);
598
+}
599
+
396 600
 
397 601
 /** rpc t_uac version-
398 602
  * It expects the following list of strings as parameters:
... ...
@@ -433,11 +637,15 @@ static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait)
433 637
 	dlg_t dlg;
434 638
 	uac_req_t uac_req;
435 639
 	rpc_delayed_ctx_t* dctx;
640
+	str *ruid = NULL;
641
+	tm_rpc_response_t *ritem = NULL;
642
+	int rcount = 0;
643
+	void* th = NULL;
436 644
 
437 645
 	body.s=0;
438 646
 	body.len=0;
439 647
 	dctx=0;
440
-	if (reply_wait && (rpc->capabilities == 0 ||
648
+	if (reply_wait==1 && (rpc->capabilities == 0 ||
441 649
 				!(rpc->capabilities(c) & RPC_DELAYED_REPLY))) {
442 650
 		rpc->fault(c, 600, "Reply wait/async mode not supported"
443 651
 				" by this rpc transport");
... ...
@@ -538,7 +746,7 @@ static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait)
538 746
 	if(hfb.s!=NULL && hfb.len>0) uac_req.headers=&hfb;
539 747
 	uac_req.body=body.len?&body:0;
540 748
 	uac_req.dialog=&dlg;
541
-	if (reply_wait){
749
+	if (reply_wait==1){
542 750
 		dctx=rpc->delayed_ctx_new(c);
543 751
 		if (dctx==0){
544 752
 			rpc->fault(c, 500, "internal error: failed to create context");
... ...
@@ -551,22 +759,57 @@ static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait)
551 759
 		   want to still send a reply */
552 760
 		rpc=&dctx->rpc;
553 761
 		c=dctx->reply_ctx;
762
+	} else if (reply_wait==2) {
763
+		sruid_next(&_tm_rpc_sruid);
764
+		uac_req.cb = rpc_uac_block_callback;
765
+		ruid = shm_str_dup_block(&_tm_rpc_sruid.uid);
766
+		uac_req.cbp = ruid;
767
+		uac_req.cb_flags = TMCB_LOCAL_COMPLETED;
554 768
 	}
769
+
555 770
 	ret = t_uac(&uac_req);
556 771
 
557 772
 	if (ret <= 0) {
558 773
 		err_ret = err2reason_phrase(ret, &sip_error, err_buf,
559 774
 				sizeof(err_buf), "RPC/UAC") ;
560
-		if (err_ret > 0 )
561
-		{
775
+		if (err_ret > 0 ) {
562 776
 			rpc->fault(c, sip_error, "%s", err_buf);
563 777
 		} else {
564 778
 			rpc->fault(c, 500, "RPC/UAC error");
565 779
 		}
566
-		if (dctx)
780
+		if (dctx) {
567 781
 			rpc->delayed_ctx_close(dctx);
782
+		}
783
+		if(ruid) {
784
+			shm_free(ruid);
785
+		}
568 786
 		goto error01;
569 787
 	}
788
+
789
+	if(reply_wait==2) {
790
+		while(ritem==NULL && rcount<800) {
791
+			sleep_us(100000);
792
+			rcount++;
793
+			ritem = tm_rpc_response_list_get(&_tm_rpc_sruid.uid);
794
+		}
795
+		if(ritem == NULL) {
796
+			rpc->fault(c, 500, "No response");
797
+		} else {
798
+			/* add structure node */
799
+			if (rpc->add(c, "{", &th) < 0) {
800
+				rpc->fault(c, 500, "Structure error");
801
+			} else {
802
+				if(rpc->struct_add(th, "dS",
803
+						"code", 	ritem->rcode,
804
+						"text", 	&ritem->rtext)<0) {
805
+					rpc->fault(c, 500, "Fields error");
806
+					return;
807
+				}
808
+			}
809
+			shm_free(ritem);
810
+		}
811
+	}
812
+
570 813
 error01:
571 814
 	if (hfb.s) pkg_free(hfb.s);
572 815
 error:
... ...
@@ -590,6 +833,14 @@ void rpc_t_uac_wait(rpc_t* rpc, void* c)
590 833
 	rpc_t_uac(rpc, c, 1);
591 834
 }
592 835
 
836
+/** t_uac with blocking for reply waiting.
837
+ * @see rpc_t_uac.
838
+ */
839
+void rpc_t_uac_wait_block(rpc_t* rpc, void* c)
840
+{
841
+	rpc_t_uac(rpc, c, 2);
842
+}
843
+
593 844
 
594 845
 static int t_uac_check_msg(struct sip_msg* msg,
595 846
 		str* method, str* body,
... ...
@@ -21,8 +21,12 @@
21 21
 #include "../../core/rpc.h"
22 22
 
23 23
 
24
+int tm_rpc_response_list_init(void);
25
+int tm_rpc_response_list_destroy(void);
26
+
24 27
 void rpc_t_uac_start(rpc_t* rpc, void* c);
25 28
 void rpc_t_uac_wait(rpc_t* rpc, void* c);
29
+void rpc_t_uac_wait_block(rpc_t* rpc, void* c);
26 30
 
27 31
 int t_uac_send(str *method, str *ruri, str *nexthop, str *send_socket,
28 32
 		str *headers, str *body);
... ...
@@ -723,6 +723,11 @@ static int mod_init(void)
723 723
 		return -1;
724 724
 	}
725 725
 
726
+	if(tm_rpc_response_list_init()<0) {
727
+		LM_ERR("failed to init rpc\n");
728
+		return -1;
729
+	}
730
+
726 731
 	if(on_sl_reply_name.s!=NULL && on_sl_reply_name.len>0) {
727 732
 		keng = sr_kemi_eng_get();
728 733
 		if(keng==NULL) {
... ...
@@ -2767,6 +2772,13 @@ static const char* rpc_t_uac_wait_doc[2] = {
2767 2772
 	0
2768 2773
 };
2769 2774
 
2775
+static const char* rpc_t_uac_wait_block_doc[2] = {
2776
+	"starts a tm uac and waits for the final reply in blocking mode, using a"
2777
+		" list of string parameters: method, ruri, dst_uri send_sock, headers"
2778
+		" (CRLF separated) and body (optional)",
2779
+	0
2780
+};
2781
+
2770 2782
 static const char* tm_rpc_list_doc[2] = {
2771 2783
 	"List transactions.",
2772 2784
 	0
... ...
@@ -2787,6 +2799,7 @@ static rpc_export_t tm_rpc[] = {
2787 2799
 	{"tm.hash_stats",  tm_rpc_hash_stats, tm_rpc_hash_stats_doc, 0},
2788 2800
 	{"tm.t_uac_start", rpc_t_uac_start, rpc_t_uac_start_doc, 0 },
2789 2801
 	{"tm.t_uac_wait",  rpc_t_uac_wait,  rpc_t_uac_wait_doc, RET_ARRAY},
2802
+	{"tm.t_uac_wait_block",  rpc_t_uac_wait_block,  rpc_t_uac_wait_block_doc, 0},
2790 2803
 	{"tm.list",  tm_rpc_list,  tm_rpc_list_doc, RET_ARRAY},
2791 2804
 	{"tm.clean", tm_rpc_clean,  tm_rpc_clean_doc, 0},
2792 2805
 	{0, 0, 0, 0}