Browse code

htable: initial dmq integration

Charles Chance authored on 07/10/2013 06:44:38
Showing 8 changed files
... ...
@@ -16,4 +16,5 @@ SERLIBPATH=../../lib
16 16
 SER_LIBS+=$(SERLIBPATH)/kmi/kmi
17 17
 SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
18 18
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
19
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
19 20
 include ../../Makefile.modules
... ...
@@ -28,6 +28,7 @@
28 28
 
29 29
 #include "ht_api.h"
30 30
 #include "api.h"
31
+#include "ht_dmq.h"
31 32
 
32 33
 /**
33 34
  *
... ...
@@ -39,6 +40,11 @@ int ht_api_set_cell(str *hname, str *name, int type,
39 39
 	ht = ht_get_table(hname);
40 40
 	if(ht==NULL)
41 41
 		return -1;
42
+
43
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, hname, name, type, val, mode)!=0) {
44
+		LM_ERR("dmq relication failed\n");
45
+	}
46
+
42 47
 	return ht_set_cell(ht, name, type, val, mode);
43 48
 }
44 49
 
... ...
@@ -51,6 +57,9 @@ int ht_api_del_cell(str *hname, str *name)
51 51
 	ht = ht_get_table(hname);
52 52
 	if(ht==NULL)
53 53
 		return -1;
54
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_DEL_CELL, hname, name, 0, NULL, 0)!=0) {
55
+		LM_ERR("dmq relication failed\n");
56
+	}
54 57
 	return ht_del_cell(ht, name);
55 58
 }
56 59
 
... ...
@@ -64,6 +73,9 @@ int ht_api_set_cell_expire(str *hname, str *name,
64 64
 	ht = ht_get_table(hname);
65 65
 	if(ht==NULL)
66 66
 		return -1;
67
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL_EXPIRE, hname, name, type, val, 0)!=0) {
68
+		LM_ERR("dmq relication failed\n");
69
+	}
67 70
 	return ht_set_cell_expire(ht, name, type, val);
68 71
 }
69 72
 
... ...
@@ -86,9 +98,17 @@ int ht_api_get_cell_expire(str *hname, str *name,
86 86
 int ht_api_rm_cell_re(str *hname, str *sre, int mode)
87 87
 {
88 88
 	ht_t* ht;
89
+	int_str isval;
89 90
 	ht = ht_get_table(hname);
90 91
 	if(ht==NULL)
91 92
 		return -1;
93
+	if (ht->dmqreplicate>0) {
94
+		isval.s.s = sre->s;
95
+		isval.s.len = sre->len;
96
+		if (ht_dmq_replicate_action(HT_DMQ_RM_CELL_RE, hname, NULL, AVP_VAL_STR, &isval, mode)!=0) {
97
+			LM_ERR("dmq relication failed\n");
98
+		}
99
+	}
92 100
 	if(ht_rm_cell_re(sre, ht, mode /* 0 - name; 1 - value */)<0)
93 101
 		return -1;
94 102
 	return 0;
... ...
@@ -218,7 +218,7 @@ ht_t* ht_get_table(str *name)
218 218
 }
219 219
 
220 220
 int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode,
221
-		int itype, int_str *ival, int updateexpire)
221
+		int itype, int_str *ival, int updateexpire, int dmqreplicate)
222 222
 {
223 223
 	unsigned int htid;
224 224
 	ht_t *ht;
... ...
@@ -261,7 +261,7 @@ int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode,
261 261
 	ht->flags = itype;
262 262
 	if(ival!=NULL)
263 263
 		ht->initval = *ival;
264
-
264
+	ht->dmqreplicate = dmqreplicate;
265 265
 	ht->next = _ht_root;
266 266
 	_ht_root = ht;
267 267
 	return 0;
... ...
@@ -761,6 +761,7 @@ int ht_table_spec(char *spec)
761 761
 	unsigned int size = 4;
762 762
 	unsigned int dbmode = 0;
763 763
 	unsigned int updateexpire = 1;
764
+	unsigned int dmqreplicate = 0;
764 765
 	str in;
765 766
 	str tok;
766 767
 	param_t *pit=NULL;
... ...
@@ -817,11 +818,16 @@ int ht_table_spec(char *spec)
817 817
 				goto error;
818 818
 
819 819
 			LM_DBG("htable [%.*s] - updateexpire [%u]\n", name.len, name.s, updateexpire); 
820
+		} else if(pit->name.len == 12 && strncmp(pit->name.s, "dmqreplicate", 12) == 0) {
821
+			if(str2int(&tok, &dmqreplicate) != 0)
822
+				goto error;
823
+
824
+			LM_DBG("htable [%.*s] - dmqreplicate [%u]\n", name.len, name.s, dmqreplicate); 
820 825
 		} else { goto error; }
821 826
 	}
822 827
 
823 828
 	return ht_add_table(&name, autoexpire, &dbtable, size, dbmode,
824
-			itype, &ival, updateexpire);
829
+			itype, &ival, updateexpire, dmqreplicate);
825 830
 
826 831
 error:
827 832
 	LM_ERR("invalid htable parameter [%.*s]\n", in.len, in.s);
... ...
@@ -62,6 +62,7 @@ typedef struct _ht
62 62
 	int_str initval;
63 63
 	int updateexpire;
64 64
 	unsigned int htsize;
65
+	int dmqreplicate;
65 66
 	ht_entry_t *entries;
66 67
 	struct _ht *next;
67 68
 } ht_t;
... ...
@@ -73,7 +74,7 @@ typedef struct _ht_pv {
73 73
 } ht_pv_t, *ht_pv_p;
74 74
 
75 75
 int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode,
76
-		int itype, int_str *ival, int updateexpire);
76
+		int itype, int_str *ival, int updateexpire, int dmqreplicate);
77 77
 int ht_init_tables(void);
78 78
 int ht_destroy(void);
79 79
 int ht_set_cell(ht_t *ht, str *name, int type, int_str *val, int mode);
80 80
new file mode 100644
... ...
@@ -0,0 +1,282 @@
0
+/**
1
+ * 
2
+ * Copyright (C) 2013 Charles Chance (Sipcentric Ltd)
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License 
17
+ * along with this program; if not, write to the Free Software 
18
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
+ *
20
+ */
21
+
22
+
23
+#include "ht_dmq.h"
24
+#include "ht_api.h"
25
+
26
+static str ht_dmq_content_type = str_init("application/json");
27
+static str dmq_200_rpl  = str_init("OK");
28
+static str dmq_400_rpl  = str_init("Bad Request");
29
+static str dmq_500_rpl  = str_init("Server Internal Error");
30
+
31
+typedef struct _ht_dmq_repdata {
32
+	int action;
33
+	str htname;
34
+	str cname;
35
+	int type;
36
+	int intval;
37
+	str strval;
38
+	int expire;
39
+} ht_dmq_repdata_t;
40
+
41
+dmq_api_t ht_dmqb;
42
+dmq_peer_t* ht_dmq_peer = NULL;
43
+dmq_resp_cback_t ht_dmq_resp_callback = {&ht_dmq_resp_callback_f, 0};
44
+
45
+/**
46
+ * @brief add notification peer
47
+ */
48
+int ht_dmq_initialize()
49
+{
50
+	dmq_peer_t not_peer;
51
+
52
+        /* load the DMQ API */
53
+        if (dmq_load_api(&ht_dmqb)!=0) {
54
+                LM_ERR("cannot load dmq api\n");
55
+                return -1;
56
+        } else {
57
+                LM_DBG("loaded dmq api\n");
58
+        }
59
+
60
+	not_peer.callback = ht_dmq_handle_msg;
61
+	not_peer.description.s = "htable";
62
+	not_peer.description.len = 6;
63
+	not_peer.peer_id.s = "htable";
64
+	not_peer.peer_id.len = 6;
65
+	ht_dmq_peer = ht_dmqb.register_dmq_peer(&not_peer);
66
+	if(!ht_dmq_peer) {
67
+		LM_ERR("error in register_dmq_peer\n");
68
+		goto error;
69
+	} else {
70
+		LM_DBG("dmq peer registered\n");
71
+	}
72
+	return 0;
73
+error:
74
+	return -1;
75
+}
76
+
77
+int ht_dmq_broadcast(str* body) {
78
+        if (!ht_dmq_peer) {
79
+                LM_ERR("ht_dmq_peer is null!\n");
80
+                return -1;
81
+        }
82
+        LM_DBG("sending broadcast...\n");
83
+        ht_dmqb.bcast_message(ht_dmq_peer, body, 0, &ht_dmq_resp_callback, 1, &ht_dmq_content_type);
84
+        return 0;
85
+}
86
+
87
+/**
88
+ * @brief ht dmq callback
89
+ */
90
+int ht_dmq_handle_msg(struct sip_msg* msg, peer_reponse_t* resp)
91
+{
92
+	int content_length;
93
+	str body;
94
+	ht_dmq_action_t action = HT_DMQ_NONE;
95
+	str htname, cname;
96
+	int type = 0, mode = 0;
97
+	int_str val;
98
+	srjson_doc_t jdoc;
99
+	srjson_t *it = NULL;
100
+
101
+	/* received dmq message */
102
+	LM_DBG("dmq message received\n");
103
+	/* parse the message headers */
104
+	if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
105
+		LM_ERR("error parsing message headers\n");
106
+		goto error;
107
+	}
108
+	
109
+	if(!msg->content_length) {
110
+		LM_ERR("no content length header found\n");
111
+		goto invalid;
112
+	}
113
+	content_length = get_content_length(msg);
114
+	if(!content_length) {
115
+		LM_DBG("content length is 0\n");
116
+		goto invalid;
117
+	}
118
+
119
+	body.s = get_body(msg);
120
+	body.len = content_length;
121
+
122
+	if (!body.s) {
123
+		LM_ERR("unable to get body\n");
124
+		goto error;
125
+	}
126
+
127
+	/* parse body */
128
+	LM_DBG("body: %.*s\n", body.len, body.s);	
129
+
130
+	srjson_InitDoc(&jdoc, NULL);
131
+	jdoc.buf = body;
132
+
133
+	if(jdoc.root == NULL) {
134
+		jdoc.root = srjson_Parse(&jdoc, jdoc.buf.s);
135
+		if(jdoc.root == NULL)
136
+		{
137
+			LM_ERR("invalid json doc [[%s]]\n", jdoc.buf.s);
138
+			goto invalid;
139
+		}
140
+	}
141
+
142
+	for(it=jdoc.root->child; it; it = it->next)
143
+	{
144
+		LM_DBG("found field: %s\n", it->string);
145
+		if (strcmp(it->string, "action")==0) {
146
+			action = it->valueint;
147
+		} else if (strcmp(it->string, "htname")==0) {
148
+			htname.s = it->valuestring;
149
+			htname.len = strlen(htname.s);
150
+		} else if (strcmp(it->string, "cname")==0) {
151
+			cname.s = it->valuestring;
152
+			cname.len = strlen(cname.s);
153
+		} else if (strcmp(it->string, "type")==0) {
154
+			type = it->valueint;
155
+		} else if (strcmp(it->string, "strval")==0) {
156
+			val.s.s = it->valuestring;
157
+			val.s.len = strlen(val.s.s);
158
+		} else if (strcmp(it->string, "intval")==0) {
159
+			val.n = it->valueint;
160
+		} else if (strcmp(it->string, "mode")==0) {
161
+			mode = it->valueint;
162
+		} else {
163
+			LM_ERR("unrecognized field in json object\n");
164
+			goto invalid;
165
+		}
166
+	}	
167
+
168
+	if (ht_dmq_replay_action(action, &htname, &cname, type, &val, mode)!=0) {
169
+		LM_ERR("failed to replay action\n");
170
+		goto error;
171
+	}
172
+
173
+	srjson_DestroyDoc(&jdoc);
174
+	resp->reason = dmq_200_rpl;
175
+	resp->resp_code = 200;
176
+	return 0;
177
+
178
+invalid:
179
+	srjson_DestroyDoc(&jdoc);
180
+	resp->reason = dmq_400_rpl;
181
+	resp->resp_code = 400;
182
+	return 0;
183
+
184
+error:
185
+	srjson_DestroyDoc(&jdoc);
186
+	resp->reason = dmq_500_rpl;
187
+	resp->resp_code = 500;	
188
+	return 0;
189
+}
190
+
191
+int ht_dmq_replicate_action(ht_dmq_action_t action, str* htname, str* cname, int type, int_str* val, int mode) {
192
+
193
+	srjson_doc_t jdoc;
194
+
195
+        LM_DBG("replicating action to dmq peers...\n");
196
+
197
+	srjson_InitDoc(&jdoc, NULL);
198
+
199
+	jdoc.root = srjson_CreateObject(&jdoc);
200
+	if(jdoc.root==NULL) {
201
+		LM_ERR("cannot create json root\n");
202
+		goto error;
203
+	}
204
+
205
+	srjson_AddNumberToObject(&jdoc, jdoc.root, "action", action);
206
+	srjson_AddStrToObject(&jdoc, jdoc.root, "htname", htname->s, htname->len);
207
+	if (cname!=NULL) {
208
+		srjson_AddStrToObject(&jdoc, jdoc.root, "cname", cname->s, cname->len);
209
+	}
210
+
211
+	if (action==HT_DMQ_SET_CELL || action==HT_DMQ_SET_CELL_EXPIRE || action==HT_DMQ_RM_CELL_RE) {
212
+		srjson_AddNumberToObject(&jdoc, jdoc.root, "type", type);
213
+		if (type&AVP_VAL_STR) {
214
+			srjson_AddStrToObject(&jdoc, jdoc.root, "strval", val->s.s, val->s.len);
215
+		} else {
216
+			srjson_AddNumberToObject(&jdoc, jdoc.root, "intval", val->n);
217
+		}
218
+	}
219
+
220
+	srjson_AddNumberToObject(&jdoc, jdoc.root, "mode", mode);	
221
+
222
+	jdoc.buf.s = srjson_PrintUnformatted(&jdoc, jdoc.root);
223
+	if(jdoc.buf.s!=NULL) {
224
+		jdoc.buf.len = strlen(jdoc.buf.s);
225
+		LM_DBG("sending serialized data %.*s\n", jdoc.buf.len, jdoc.buf.s);
226
+		if (ht_dmq_broadcast(&jdoc.buf)!=0) {
227
+			goto error;
228
+		}
229
+		jdoc.free_fn(jdoc.buf.s);
230
+		jdoc.buf.s = NULL;
231
+	} else {
232
+		LM_ERR("unable to serialize data\n");
233
+		goto error;
234
+	}
235
+
236
+	srjson_DestroyDoc(&jdoc);
237
+	return 0;
238
+
239
+error:
240
+	if(jdoc.buf.s!=NULL) {
241
+		jdoc.free_fn(jdoc.buf.s);
242
+		jdoc.buf.s = NULL;
243
+	}
244
+	srjson_DestroyDoc(&jdoc);
245
+	return -1;
246
+}
247
+
248
+int ht_dmq_replay_action(ht_dmq_action_t action, str* htname, str* cname, int type, int_str* val, int mode) {
249
+
250
+	ht_t* ht;
251
+	ht = ht_get_table(htname);
252
+	if(ht==NULL) {
253
+		LM_ERR("unable to get table\n");
254
+		return -1;
255
+	}
256
+
257
+        LM_DBG("replaying action %d on %.*s=>%.*s...\n", action, htname->len, htname->s, cname->len, cname->s);
258
+
259
+	if (action==HT_DMQ_SET_CELL) {
260
+		return ht_set_cell(ht, cname, type, val, mode);
261
+	} else if (action==HT_DMQ_SET_CELL_EXPIRE) {
262
+		return ht_set_cell_expire(ht, cname, 0, val);
263
+	} else if (action==HT_DMQ_DEL_CELL) {
264
+		return ht_del_cell(ht, cname);
265
+	} else if (action==HT_DMQ_RM_CELL_RE) {
266
+		return ht_rm_cell_re(&val->s, ht, mode);
267
+	} else {
268
+		LM_ERR("unrecognized action");
269
+		return -1;
270
+	}
271
+}
272
+
273
+/**
274
+ * @brief dmq response callback
275
+ */
276
+int ht_dmq_resp_callback_f(struct sip_msg* msg, int code,
277
+		dmq_node_t* node, void* param)
278
+{
279
+	LM_DBG("dmq response callback triggered [%p %d %p]\n", msg, code, param);
280
+	return 0;
281
+}
0 282
new file mode 100644
... ...
@@ -0,0 +1,48 @@
0
+/**
1
+ *
2
+ * Copyright (C) 2013 Charles Chance (Sipcentric Ltd)
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License 
17
+ * along with this program; if not, write to the Free Software 
18
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
+ */
20
+
21
+#ifndef _HT_DMQ_H_
22
+#define _HT_DMQ_H_
23
+
24
+#include "../dmq/bind_dmq.h"
25
+#include "../../lib/srutils/srjson.h"
26
+#include "../../parser/msg_parser.h"
27
+#include "../../parser/parse_content.h"
28
+
29
+extern dmq_api_t ht_dmqb;
30
+extern dmq_peer_t* ht_dmq_peer;
31
+extern dmq_resp_cback_t ht_dmq_resp_callback;
32
+
33
+typedef enum {
34
+		HT_DMQ_NONE,
35
+        HT_DMQ_SET_CELL,
36
+        HT_DMQ_SET_CELL_EXPIRE,
37
+        HT_DMQ_DEL_CELL,
38
+        HT_DMQ_RM_CELL_RE
39
+} ht_dmq_action_t;
40
+
41
+int ht_dmq_initialize();
42
+int ht_dmq_handle_msg(struct sip_msg* msg, peer_reponse_t* resp);
43
+int ht_dmq_replicate_action(ht_dmq_action_t action, str* htname, str* cname, int type, int_str* val, int mode);
44
+int ht_dmq_replay_action(ht_dmq_action_t action, str* htname, str* cname, int type, int_str* val, int mode);
45
+int ht_dmq_resp_callback_f(struct sip_msg* msg, int code, dmq_node_t* node, void* param);
46
+
47
+#endif
... ...
@@ -22,6 +22,7 @@
22 22
 		       
23 23
 #include "ht_api.h"
24 24
 #include "ht_var.h"
25
+#include "ht_dmq.h"
25 26
 
26 27
 /* pkg copy */
27 28
 ht_cell_t *_htc_local=NULL;
... ...
@@ -90,6 +91,9 @@ int pv_set_ht_cell(struct sip_msg* msg, pv_param_t *param,
90 90
 	if((val==NULL) || (val->flags&PV_VAL_NULL))
91 91
 	{
92 92
 		/* delete it */
93
+		if (hpv->ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_DEL_CELL, &hpv->htname, &htname, 0, NULL, 0)!=0) {
94
+			LM_ERR("dmq relication failed\n");
95
+		}
93 96
 		ht_del_cell(hpv->ht, &htname);
94 97
 		return 0;
95 98
 	}
... ...
@@ -97,6 +101,9 @@ int pv_set_ht_cell(struct sip_msg* msg, pv_param_t *param,
97 97
 	if(val->flags&PV_TYPE_INT)
98 98
 	{
99 99
 		isval.n = val->ri;
100
+		if (hpv->ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, &hpv->htname, &htname, 0, &isval, 1)!=0) {
101
+			LM_ERR("dmq relication failed\n");
102
+		}
100 103
 		if(ht_set_cell(hpv->ht, &htname, 0, &isval, 1)!=0)
101 104
 		{
102 105
 			LM_ERR("cannot set $ht(%.*s)\n", htname.len, htname.s);
... ...
@@ -104,6 +111,9 @@ int pv_set_ht_cell(struct sip_msg* msg, pv_param_t *param,
104 104
 		}
105 105
 	} else {
106 106
 		isval.s = val->rs;
107
+		if (hpv->ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, &hpv->htname, &htname, AVP_VAL_STR, &isval, 1)!=0) {
108
+			LM_ERR("dmq relication failed\n");
109
+		}
107 110
 		if(ht_set_cell(hpv->ht, &htname, AVP_VAL_STR, &isval, 1)!=0)
108 111
 		{
109 112
 			LM_ERR("cannot set $ht(%.*s)\n", htname.len, htname.s);
... ...
@@ -229,6 +239,9 @@ int pv_set_ht_cell_expire(struct sip_msg* msg, pv_param_t *param,
229 229
 		if(val->flags&PV_TYPE_INT)
230 230
 			isval.n = val->ri;
231 231
 	}
232
+	if (hpv->ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL_EXPIRE, &hpv->htname, &htname, 0, &isval, 0)!=0) {
233
+		LM_ERR("dmq relication failed\n");
234
+	}	
232 235
 	if(ht_set_cell_expire(hpv->ht, &htname, 0, &isval)!=0)
233 236
 	{
234 237
 		LM_ERR("cannot set $ht(%.*s)\n", htname.len, htname.s);
... ...
@@ -327,6 +340,11 @@ int pv_get_ht_add(struct sip_msg *msg,  pv_param_t *param,
327 327
 		return pv_get_null(msg, param, res);
328 328
 
329 329
 	/* integer */
330
+	if (hpv->ht->dmqreplicate>0) {
331
+		if (ht_dmq_replicate_action(HT_DMQ_SET_CELL, &hpv->htname, &htname, 0, &htc->value, 1)!=0) {
332
+			LM_ERR("dmq relication failed\n");
333
+		}
334
+	}	
330 335
 	return pv_get_sintval(msg, param, res, htc->value.n);
331 336
 }
332 337
 
... ...
@@ -44,12 +44,14 @@
44 44
 #include "ht_db.h"
45 45
 #include "ht_var.h"
46 46
 #include "api.h"
47
+#include "ht_dmq.h"
47 48
 
48 49
 
49 50
 MODULE_VERSION
50 51
 
51 52
 int  ht_timer_interval = 20;
52 53
 int  ht_db_expires_flag = 0;
54
+int  ht_enable_dmq = 0;
53 55
 
54 56
 static int htable_init_rpc(void);
55 57
 
... ...
@@ -124,6 +126,7 @@ static param_export_t params[]={
124 124
 	{"fetch_rows",         INT_PARAM, &ht_fetch_rows},
125 125
 	{"timer_interval",     INT_PARAM, &ht_timer_interval},
126 126
 	{"db_expires",         INT_PARAM, &ht_db_expires_flag},
127
+	{"enable_dmq",         INT_PARAM, &ht_enable_dmq},
127 128
 	{0,0,0}
128 129
 };
129 130
 
... ...
@@ -188,6 +191,12 @@ static int mod_init(void)
188 188
 			return -1;
189 189
 		}
190 190
 	}
191
+
192
+	if (ht_enable_dmq>0 && ht_dmq_initialize()!=0) {
193
+		LM_ERR("failed to initialize dmq integration\n");
194
+		return -1;
195
+	}
196
+
191 197
 	return 0;
192 198
 }
193 199
 
... ...
@@ -286,6 +295,7 @@ static int ht_rm_name_re(struct sip_msg* msg, char* key, char* foo)
286 286
 	str sre;
287 287
 	pv_spec_t *sp;
288 288
 	sp = (pv_spec_t*)key;
289
+	int_str isval;
289 290
 
290 291
 	hpv = (ht_pv_t*)sp->pvp.pvn.u.dname;
291 292
 
... ...
@@ -300,6 +310,12 @@ static int ht_rm_name_re(struct sip_msg* msg, char* key, char* foo)
300 300
 		LM_ERR("cannot get $ht expression\n");
301 301
 		return -1;
302 302
 	}
303
+	if (hpv->ht->dmqreplicate>0) {
304
+		isval.s = sre;
305
+		if (ht_dmq_replicate_action(HT_DMQ_RM_CELL_RE, &hpv->htname, NULL, AVP_VAL_STR, &isval, 0)!=0) {
306
+			LM_ERR("dmq relication failed\n");
307
+		}
308
+	}
303 309
 	if(ht_rm_cell_re(&sre, hpv->ht, 0)<0)
304 310
 		return -1;
305 311
 	return 1;
... ...
@@ -311,6 +327,7 @@ static int ht_rm_value_re(struct sip_msg* msg, char* key, char* foo)
311 311
 	str sre;
312 312
 	pv_spec_t *sp;
313 313
 	sp = (pv_spec_t*)key;
314
+	int_str isval;
314 315
 
315 316
 	hpv = (ht_pv_t*)sp->pvp.pvn.u.dname;
316 317
 
... ...
@@ -326,6 +343,12 @@ static int ht_rm_value_re(struct sip_msg* msg, char* key, char* foo)
326 326
 		return -1;
327 327
 	}
328 328
 
329
+	if (hpv->ht->dmqreplicate>0) {
330
+		isval.s = sre;
331
+		if (ht_dmq_replicate_action(HT_DMQ_RM_CELL_RE, &hpv->htname, NULL, AVP_VAL_STR, &isval, 1)!=0) {
332
+			LM_ERR("dmq relication failed\n");
333
+		}
334
+	}
329 335
 	if(ht_rm_cell_re(&sre, hpv->ht, 1)<0)
330 336
 		return -1;
331 337
 	return 1;
... ...
@@ -531,6 +554,10 @@ static struct mi_root* ht_mi_delete(struct mi_root* cmd_tree, void* param) {
531 531
 	if (!ht)
532 532
 		return init_mi_tree(404, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
533 533
 
534
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_DEL_CELL, &ht->name, key, 0, NULL, 0)!=0) {
535
+		LM_ERR("dmq relication failed\n");
536
+	}
537
+
534 538
 	ht_del_cell(ht, key);
535 539
 
536 540
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
... ...
@@ -655,6 +682,10 @@ static void htable_rpc_delete(rpc_t* rpc, void* c) {
655 655
 		return;
656 656
 	}
657 657
 
658
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_DEL_CELL, &ht->name, &keyname, 0, NULL, 0)!=0) {
659
+		LM_ERR("dmq relication failed\n");
660
+	}
661
+
658 662
 	ht_del_cell(ht, &keyname);
659 663
 }
660 664
 
... ...
@@ -737,6 +768,10 @@ static void htable_rpc_sets(rpc_t* rpc, void* c) {
737 737
 		return;
738 738
 	}
739 739
 	
740
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, &ht->name, &keyname, AVP_VAL_STR, &keyvalue, 1)!=0) {
741
+		LM_ERR("dmq relication failed\n");
742
+	}
743
+
740 744
 	if(ht_set_cell(ht, &keyname, AVP_VAL_STR, &keyvalue, 1)!=0)
741 745
 	{
742 746
 		LM_ERR("cannot set $ht(%.*s=>%.*s)\n", htname.len, htname.s,
... ...
@@ -766,6 +801,10 @@ static void htable_rpc_seti(rpc_t* rpc, void* c) {
766 766
 		rpc->fault(c, 500, "No such htable");
767 767
 		return;
768 768
 	}
769
+
770
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, &ht->name, &keyname, 0, &keyvalue, 1)!=0) {
771
+		LM_ERR("dmq relication failed\n");
772
+	}
769 773
 	
770 774
 	if(ht_set_cell(ht, &keyname, 0, &keyvalue, 1)!=0)
771 775
 	{
... ...
@@ -886,13 +925,14 @@ static void  htable_rpc_list(rpc_t* rpc, void* c)
886 886
 			dbname[0] = '\0';
887 887
 		}
888 888
 
889
-		if(rpc->struct_add(th, "Ssdddd",
889
+		if(rpc->struct_add(th, "Ssddddd",
890 890
 						"name", &ht->name,	/* String */
891 891
 						"dbtable", &dbname ,	/* Char * */
892 892
 						"dbmode", (int)  ht->dbmode,		/* u int */
893 893
 						"expire", (int) ht->htexpire,		/* u int */
894 894
 						"updateexpire", ht->updateexpire,	/* int */
895
-						"size", (int) ht->htsize		/* u int */
895
+						"size", (int) ht->htsize,			/* u int */
896
+						"dmqreplicate", ht->dmqreplicate	/* int */
896 897
 						) < 0) {
897 898
 			rpc->fault(c, 500, "Internal error creating data rpc");
898 899
 			goto error;