Browse code

smsops: Added an example configuration for an Interworking SMSc-AS

Carsten Bock authored on 11/06/2015 10:42:52
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,418 @@
0
+#!KAMAILIO
1
+#
2
+# This config file implements the basic P-CSCF functionality
3
+#     - web: http://www.kamailio.org
4
+#     - git: http://sip-router.org
5
+#
6
+# Refer to the Core CookBook at http://www.kamailio.org/dokuwiki/doku.php
7
+# for an explanation of possible statements, functions and parameters.
8
+#
9
+# Direct your questions about this file to: <sr-users@lists.sip-router.org>.
10
+#
11
+# For more information about the various parameters, functions and statements
12
+# try http://sip-router.org/wiki/ .
13
+#
14
+
15
+include_file "smsc.cfg"
16
+
17
+####### Global Parameters #########
18
+debug=2
19
+log_stderror=no
20
+sip_warning=no
21
+children=4
22
+
23
+user_agent_header="User-Agent: Kamailio SMSC"
24
+server_header="Server: Kamailio SMSC"
25
+
26
+/* comment the next line to enable the auto discovery of local aliases
27
+   based on reverse DNS on IPs (default on) */
28
+auto_aliases=no
29
+
30
+check_via=no    # (cmd. line: -v)
31
+dns=no          # (cmd. line: -r)
32
+rev_dns=no      # (cmd. line: -R)
33
+tcp_accept_no_cl=yes
34
+
35
+#!define SMS_3GPP 1
36
+#!define SMS_TEXT 2
37
+
38
+alias=SERVER
39
+
40
+# ------------------ module loading ----------------------------------
41
+mpath="/root/kamailio-devel/lib64/kamailio/modules"
42
+# (we try both the lib64 and the lib directory)
43
+
44
+loadmodule "tm"
45
+loadmodule "tmx"
46
+loadmodule "smsops"
47
+loadmodule "xlog"
48
+loadmodule "maxfwd"
49
+loadmodule "textops"
50
+loadmodule "sl"
51
+loadmodule "sanity"
52
+loadmodule "siputils"
53
+loadmodule "pv"
54
+loadmodule "uac"
55
+loadmodule "xhttp"
56
+loadmodule "utils"
57
+loadmodule "json"
58
+loadmodule "enum"
59
+loadmodule "db_mysql"
60
+loadmodule "dialplan"
61
+loadmodule "sqlops"
62
+loadmodule "htable"
63
+loadmodule "rtimer"
64
+loadmodule "usrloc"
65
+loadmodule "registrar"
66
+loadmodule "pua"
67
+loadmodule "pua_reginfo"
68
+
69
+modparam("sqlops","sqlcon","sms=>mysql://root@localhost/smsc")
70
+modparam("dialplan|pua", "db_url", "mysql://root@localhost/kamailio")
71
+modparam("uac","restore_mode","none")
72
+modparam("enum", "domain_suffix", "DOMAIN.")
73
+
74
+modparam("htable", "htable", "publish_sent=>size=8;autoexpire=SUBSCRIBE_EXPIRE")
75
+
76
+# time interval set to 3 seconds
77
+modparam("rtimer", "timer", "name=sms;interval=3;mode=1;")
78
+modparam("rtimer", "exec", "timer=sms;route=SMS_WORKER")
79
+
80
+modparam("pua_reginfo", "server_address", "sip:reginfo@DOMAIN")
81
+modparam("pua_reginfo", "publish_reginfo", 0)
82
+
83
+####### Routing Logic ########
84
+# Main SIP request routing logic
85
+# - processing of any incoming SIP request starts with this route
86
+
87
+route {
88
+	xlog("L_DBG", "$rm ($fu ($si:$sp) to $tu, $ci)\n");
89
+
90
+	# per request initial checks
91
+	route(REQINIT);
92
+
93
+	if (is_method("NOTIFY")) {
94
+		route(NOTIFY);
95
+		send_reply("202", "Accepted");
96
+		exit;
97
+	}
98
+
99
+	if (!is_method("MESSAGE")) {
100
+		append_to_reply("Allow: MESSAGE,NOTIFY\r\n");
101
+		send_reply("405", "Method not allowed");
102
+		exit;
103
+	}
104
+
105
+	if ($cT == "application/vnd.3gpp.sms") {
106
+		route(SMS_FROM_3GPP);
107
+	} else if ($cT == "text/plain") {
108
+		route(SMS_FROM_SIP);
109
+	} else {
110
+		send_reply("488", "Content-Type not supported");
111
+		exit;
112
+	}
113
+}
114
+
115
+######################################################################
116
+# Helper routes (Basic-Checks, NAT-Handling/RTP-Control, XML-RPC)
117
+######################################################################
118
+# Per SIP request initial checks
119
+route[REQINIT] {
120
+	# Trace this message
121
+
122
+	if (!mf_process_maxfwd_header("10")) {
123
+		sl_send_reply("483","Too Many Hops");
124
+		exit;
125
+	}
126
+
127
+	if(!sanity_check("1511", "7")) {
128
+		xlog("Malformed SIP message from $si:$sp\n");
129
+		exit;
130
+	}
131
+
132
+	# Reply to OPTIONS:
133
+	if (is_method("OPTIONS") && (uri==myself)) {
134
+		options_reply();
135
+		exit;
136
+	}	
137
+
138
+	# Ignore Re-Transmits:
139
+	if (t_lookup_request()) {
140
+		exit;
141
+	}
142
+}
143
+
144
+######################################################################
145
+# SMS from VoLTE Handsets
146
+######################################################################
147
+route[SMS_FROM_3GPP] {
148
+#!ifdef WITH_DEBUG
149
+	xlog("3GPP-SMS: $rm ($fu ($si:$sp) to $tu, $ci)\n");
150
+	xlog("SMS for $tpdu(destination) \"$tpdu(payload)\" (Valid: $tpdu(validity) )\n");
151
+#!endif
152
+	send_reply("202", "Accepted");
153
+
154
+	if (isRPDATA()) {
155
+		$uac_req(method) = "MESSAGE";
156
+		$uac_req(ruri) = $ai;
157
+		$uac_req(furi) = $ai;
158
+		$uac_req(turi) = $ai;
159
+		$uac_req(hdrs) = "Content-Type: application/vnd.3gpp.sms\r\nRequest-Disposition: fork, parallel\r\nAccept-Contact: *;+g.3gpp.smsip;require;explicit\r\n";
160
+		$uac_req(body) = $smsack;
161
+		uac_req_send();
162
+
163
+
164
+		$avp(from) = $(ai{uri.user});
165
+		$avp(to) = $tpdu(destination);
166
+		# Translate "To":
167
+		dp_translate("1", "$avp(to)/$avp(to)");
168
+			
169
+		$avp(text) = $tpdu(payload);
170
+#!ifdef WITH_DEBUG
171
+		xlog("SMS from 3GPP/VoLTE\n");
172
+		xlog("-------------------------------------\n");
173
+		xlog("FROM $avp(from)\n");
174
+		xlog("TO   $avp(to)\n");
175
+		xlog("TEXT $avp(text)\n");
176
+#!endif
177
+		route(SMS);
178
+	}
179
+
180
+	exit;
181
+}
182
+
183
+######################################################################
184
+# SMS from OTT Handsets
185
+######################################################################
186
+route[SMS_FROM_SIP] {
187
+	send_reply("200", "OK");
188
+
189
+	$avp(from) = $(ai{uri.user});
190
+	# Translate "To":
191
+	$avp(to) = $tU;
192
+	dp_translate("1", "$avp(to)/$avp(to)");
193
+	$avp(text) = $rb;
194
+#!ifdef WITH_DEBUG
195
+	xlog("SMS from SIP/OTT\n");
196
+	xlog("-------------------------------------\n");
197
+	xlog("FROM $avp(from)\n");
198
+	xlog("TO   $avp(to)\n");
199
+	xlog("TEXT $avp(text)\n");
200
+#!endif
201
+	route(SMS);
202
+
203
+	exit;
204
+}
205
+
206
+
207
+######################################################################
208
+# SMS from other networks
209
+######################################################################
210
+event_route[xhttp:request] {
211
+	if ($(hu{url.querystring}{s.len}) > 0) {
212
+		$avp(from) = $(hu{url.querystring}{param.value,msisdn,&});
213
+		$avp(to) = $(hu{url.querystring}{param.value,to,&});
214
+		$avp(text) = $(hu{url.querystring}{param.value,text,&}{s.replace,+,%20}{s.unescape.user});
215
+		$avp(from_outbound) = 1;
216
+#!ifdef WITH_DEBUG
217
+		xlog("SMS from Outbound ($hu)\n");
218
+		xlog("-------------------------------------\n");
219
+		xlog("FROM $avp(from)\n");
220
+		xlog("TO   $avp(to)\n");
221
+		xlog("TEXT $avp(text)\n");
222
+#!endif
223
+	if ($avp(to) == "491771782261")
224
+		$avp(to) = "494046895124"; 
225
+	if ($avp(to) == "491771782319") 
226
+		$avp(to) = "494034927220";
227
+
228
+		route(SMS);
229
+	}
230
+
231
+	xhttp_reply("200", "OK", "text/html", "<html><body>OK - [$si:$sp]</body></html>");
232
+}
233
+
234
+######################################################################
235
+# SMS to VoLTE Handsets
236
+######################################################################
237
+route[SMS_TO_3GPP] {
238
+#!ifdef WITH_DEBUG
239
+	xlog("SMS to 3GPP/VoLTE\n");
240
+	xlog("-------------------------------------\n");
241
+	xlog("FROM $avp(from)\n");
242
+	xlog("TO   $avp(to)\n");
243
+	xlog("TEXT $avp(text)\n");
244
+#!endif
245
+
246
+	// Construct a new SMS-Body:
247
+	$rpdata(all) = $null;
248
+	$rpdata(type) = 1; // RP-DATA: Network to UE
249
+	$rpdata(reference) = $avp(id);
250
+	$rpdata(originator) = $avp(from);
251
+	$tpdu(type) = 4; // SMS-Deliver
252
+	$tpdu(origen) = $avp(from); // The Destination becomes the originator of the SMS
253
+	$tpdu(payload) = $avp(text);
254
+
255
+	$uac_req(method) = "MESSAGE";
256
+	$uac_req(ruri) = "sip:"+$avp(to)+"@"+DOMAIN;
257
+	$uac_req(furi) = "sip:"+$avp(to)+"@"+DOMAIN;
258
+	$uac_req(turi) = "sip:"+$avp(to)+"@"+DOMAIN;
259
+	$uac_req(hdrs) = "Content-Type: application/vnd.3gpp.sms\r\nRequest-Disposition: fork, parallel\r\nAccept-Contact: *;+g.3gpp.smsip;require;explicit\r\nX-MSG-ID: "+$avp(id)+"\r\n";
260
+	$uac_req(body) = $smsbody;
261
+	$uac_req(evroute)=1;
262
+	uac_req_send();
263
+	sql_query("sms", "delete from messages where id=$avp(id);");
264
+}
265
+
266
+######################################################################
267
+# SMS to OTT-Handsets
268
+######################################################################
269
+route[SMS_TO_SIP] {
270
+#!ifdef WITH_DEBUG
271
+	xlog("SMS to SIP/OTT\n");
272
+	xlog("-------------------------------------\n");
273
+	xlog("FROM $avp(from)\n");
274
+	xlog("TO   $avp(to)\n");
275
+	xlog("TEXT $avp(text)\n");
276
+#!endif
277
+
278
+	$uac_req(method) = "MESSAGE";
279
+	$uac_req(ruri) = "sip:"+$avp(to)+"@"+DOMAIN;
280
+	$uac_req(furi) = "sip:+"+$avp(from)+"@"+DOMAIN;
281
+	$uac_req(turi) = "sip:"+$avp(to)+"@"+DOMAIN;
282
+	$uac_req(hdrs) = "Content-Type: text/plain\r\nX-MSG-ID: "+$avp(id)+"\r\n";
283
+	$uac_req(evroute)=1;
284
+	$uac_req(body) = $avp(text);
285
+
286
+	uac_req_send();
287
+}
288
+
289
+######################################################################
290
+# SMS to Outbound
291
+######################################################################
292
+route[SMS_TO_OUTBOUND] {
293
+#!ifdef WITH_DEBUG
294
+	xlog("SMS to Outbound\n");
295
+	xlog("-------------------------------------\n");
296
+	xlog("FROM $avp(from)\n");
297
+	xlog("TO   $avp(to)\n");
298
+	xlog("TEXT $avp(text)\n");
299
+#!endif
300
+	if ($avp(from_outbound) == 1) {
301
+		xlog("Not sending: FROM and TO Outbound!\n");
302
+		return 1;
303
+		exit;
304
+	}
305
+	if ($avp(from) == "494046895124")
306
+		$avp(from) = "491771782261";
307
+	if ($avp(from) == "494034927220")
308
+		$avp(from) = "491771782319";
309
+
310
+	http_query("https://rest.nexmo.com/sms/json?api_key=NEXMO_APIKEY&api_secret=NEXMO_APISECRET&from=$avp(from)&to=$avp(to)&text=$(avp(text){s.escape.user})", "$var(result)");
311
+	if ($retcode != 200) return -1;
312
+	json_get_field("$var(result)", "messages", "$var(messages)");
313
+	json_get_field("$var(messages)", "status", "$var(status)");
314
+	if ($var(status) != 0) return -1;	
315
+	return 1;
316
+}
317
+
318
+######################################################################
319
+# SMS Handling
320
+######################################################################
321
+route[SMS] {
322
+#!ifdef WITH_DEBUG
323
+	xlog("SMS-Task\n");
324
+	xlog("-------------------------------------\n");
325
+	xlog("FROM $avp(from)\n");
326
+	xlog("TO   $avp(to)\n");
327
+	xlog("TEXT $avp(text)\n");
328
+#!endif
329
+
330
+	# Query ENUM: Local number?
331
+	$var(enum) = "+"+$avp(to);
332
+	if (!enum_pv_query("$var(enum)")) {
333
+		route(SMS_TO_OUTBOUND);
334
+		return $retcode;
335
+	}
336
+	if (sql_query("sms", "insert into messages (caller, callee, text, valid) values ('$(avp(from){s.escape.common})', '$(avp(to){s.escape.common})', '$(avp(text){s.escape.common})', now());"))
337
+		return 1;
338
+	else
339
+		return -1;
340
+}
341
+
342
+######################################################################
343
+# SMS Handling
344
+######################################################################
345
+route[SMS_WORKER] {
346
+	sql_query("sms", "select id, caller, callee, text from messages;", "q");
347
+	if ($dbr(q=>rows) > 0) {
348
+		$var(i) = 0;
349
+		while ($var(i) < $dbr(q=>rows)) {
350
+			$avp(id) = $dbr(q=>[$var(i),0]);
351
+			$avp(from) = $dbr(q=>[$var(i),1]);
352
+			$avp(to) = $dbr(q=>[$var(i),2]);
353
+			$avp(text) = $dbr(q=>[$var(i),3]);
354
+
355
+			route(SEND_SMS);
356
+#!ifdef WITH_DEBUG
357
+			xlog("ID   $avp(id)\n");
358
+			xlog("FROM $avp(from)\n");
359
+			xlog("TO   $avp(to)\n");
360
+			xlog("TEXT $avp(text)\n");
361
+#!endif
362
+			$var(i) = $var(i) + 1;
363
+		}
364
+	}
365
+	sql_result_free("q");
366
+}
367
+
368
+route[NOTIFY] {
369
+	if (has_body("application/reginfo+xml")) {
370
+		if (reginfo_handle_notify("location"))
371
+			send_reply("202", "Accepted");
372
+	} else {
373
+		send_reply("503", "Invalid Content-Type");
374
+	}
375
+	exit;
376
+}
377
+
378
+route[SEND_SMS] {
379
+	$var(uri) = "sip:"+$avp(to)+"@"+DOMAIN;
380
+	
381
+	if (reg_fetch_contacts("location", "$var(uri)", "caller")) {
382
+		$var(j) = 0;
383
+		$var(is3gpp) = 0;
384
+		while($var(j) < $(ulc(caller=>count))) {
385
+			$var(k) = 0;
386
+			while($var(k) < $(ulc(caller=>addr)[$var(j)]{param.count})) {
387
+				if ($(ulc(caller=>addr)[$var(j)]{param.name,$var(k)}) == "+g.3gpp.smsip")
388
+					$var(is3gpp) = 1;
389
+				$var(k) = $var(k) + 1;
390
+			}
391
+			if ($var(is3gpp) == 1)
392
+				route(SMS_TO_3GPP);
393
+			else
394
+				route(SMS_TO_SIP);		
395
+			$var(j) = $var(j) + 1;
396
+		}
397
+	} else {
398
+		if ($sht(publish_sent=>$var(uri)) == $null) {
399
+			reginfo_subscribe("$var(uri)", "SUBSCRIBE_EXPIRE");
400
+			$sht(publish_sent=>$var(uri)) = 1;
401
+		}
402
+	}
403
+}
404
+
405
+event_route [tm:local-request] {
406
+	if (is_method("SUBSCRIBE")) {
407
+		append_hf("P-Asserted-Identity: $ru\r\n");
408
+	}
409
+}
410
+
411
+event_route[uac:reply] {
412
+	if (($uac_req(evtype) == 1) && ($uac_req(evcode) == 200)) {
413
+		$var(msgid) = $(uac_req(hdrs){line.sw,X-MSG-ID:}{s.substr,10,0}{s.int});
414
+		sql_query("sms", "delete from messages where id=$var(msgid);");
415
+	}
416
+}
417
+
0 418
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+listen=udp:127.0.0.1:5060
1
+listen=tcp:127.0.0.1:80
2
+
3
+#!substdef "/DOMAIN/ims.mnc001.mcc001.3gppnetwork.org/"
4
+#!substdef "/SERVER/smsc.ims.mnc001.mcc001.3gppnetwork.org/"
5
+#!subst "/NEXMO_APIKEY/abcdef/"
6
+#!subst "/NEXMO_APISECRET/xyz/"
7
+#!subst "/SUBSCRIBE_EXPIRE/7200/"