Browse code

Merge branch 'master' into offer_answer

Raphael Coeffic authored on 05/04/2011 12:09:31
Showing 121 changed files
... ...
@@ -14,3 +14,8 @@ getarch
14 14
 getos
15 15
 sems
16 16
 sems-stats
17
+sems-logfile-callextract
18
+
19
+cscope.out
20
+cscope.files
21
+semantic.cache
... ...
@@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
3 3
 IF(COMMAND cmake_policy)
4 4
 	# Don't do automatic escaping of variables
5 5
 	CMAKE_POLICY(SET CMP0005 OLD)
6
+	CMAKE_POLICY(SET CMP0003 NEW)
6 7
 ENDIF(COMMAND cmake_policy)
7 8
 
8 9
 
... ...
@@ -12,7 +13,7 @@ set( CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
12 13
 PROJECT (SEMS)
13 14
 
14 15
 SET(SEMS_MAJOR_VERSION 1)
15
-SET(SEMS_MINOR_VERSION 4)
16
+SET(SEMS_MINOR_VERSION 5)
16 17
 SET(SEMS_BUILD_VERSION 0)
17 18
 SET(SEMS_EXTRA_VERSION dev)
18 19
 
... ...
@@ -265,5 +266,6 @@ SET(CMAKE_SHARED_LIBRARY_PREFIX "")
265 266
 
266 267
 ADD_SUBDIRECTORY (core)
267 268
 ADD_SUBDIRECTORY (apps)
269
+ADD_SUBDIRECTORY (tools)
268 270
 
269 271
 #SET_DIRECTORY_PROPERTIES(ADDITIONAL_MAKE_CLEAN_FILES *~)
... ...
@@ -8,7 +8,7 @@ all: modules
8 8
 COREPATH=core
9 9
 include Makefile.defs
10 10
 
11
-subdirs = core apps
11
+subdirs = core apps tools
12 12
 
13 13
 .PHONY: clean
14 14
 clean:
... ...
@@ -20,7 +20,7 @@ endif
20 20
 
21 21
 #version number
22 22
 VERSION = 1
23
-PATCHLEVEL = 4
23
+PATCHLEVEL = 5
24 24
 SUBLEVEL = 0
25 25
 
26 26
 ifneq ($(SCM_REV),)
... ...
@@ -50,7 +50,7 @@ CPPFLAGS += -D_DEBUG \
50 50
 #      if compiled without thread pool support, every
51 51
 #      session will have its own thread.
52 52
 #
53
-#USE_THREADPOOL = yes
53
+USE_THREADPOOL = yes
54 54
 
55 55
 # compile with spandsp DTMF detection? see soft-switch.org
56 56
 #   this needs a fairly new version of spandsp - tested with 0.0.4pre11
... ...
@@ -13,7 +13,9 @@ Introduction:
13 13
  in VoIP networks for all applications where server-
14 14
  side processing of audio is required, for example away 
15 15
  or pre-call announcements, voicemail, or network side 
16
- conferencing. 
16
+ conferencing. Another use case is for interconnecting
17
+ SIP networks, where a back-to-back user agent (B2BUA)
18
+ is required.
17 19
 
18 20
  SEMS can be used to implement simple high performance 
19 21
  components like announcement servers as building 
... ...
@@ -22,27 +24,29 @@ Introduction:
22 24
  user agent (B2BUA) and state machine scripting functionality, 
23 25
  complex VoIP services can be realized completely in SEMS. 
24 26
  
25
- SEMS only supports patent free codecs. That means that codecs
26
- like g729 won't be supported. On the other hand, SEMS supports 
27
- all important patent free codecs out of the box (g711u, g711a, 
28
- GSM06.10, speex, G726, L16 and iLBC). Integrating other codecs 
29
- in SEMS is very simple (patented or not).
27
+ SEMS supports all important patent free codecs out of the
28
+ box (g711u, g711a, GSM06.10, speex, G.726, L16 and iLBC).
29
+ There is a wrapper for the IPP G.729 codec implementation
30
+ available. Integrating other codecs in SEMS is very simple
31
+ (patented or not).
30 32
 
31 33
  SEMS shows very good performance on current standard
32 34
  PC architecture based server systems. It has sucessfully
33 35
  been run with 1200 G.711 conference channels on a quad-core
34 36
  Intel(R) Xeon at 2GHz (700 GSM, 280 iLBC channels), and up to 
35
- 5000 channels on a dual quad Xeon at 2.9GHz. On the 
36
- other hand it also runs on very small devices - for example 
37
- small embedded systems like routers running OpenWRT, for which 
38
- of course the achievable channel count is not that high.
37
+ 5000 channels on a dual quad Xeon at 2.9GHz. Its back-to-back
38
+ user agent has been run with up to 19000 TPS on the latter
39
+ machine. On the other hand it also runs on very small devices -
40
+ for example small embedded systems like routers running OpenWRT,
41
+ for which of course the achievable channel count is not that
42
+ high.
39 43
 
40 44
 License:
41 45
 
42 46
  SEMS is free (speech+beer) software. It is licensed under dual 
43
- license terms, the GPL (v2+) and proprietary license. This program
44
- is released under the GPL with the additional exemption that
45
- compiling, linking, and/or using OpenSSL is allowed.
47
+ license terms, the GPL (v2+) and proprietary license. This
48
+ program is released under the GPL with the additional exemption
49
+ that compiling, linking, and/or using OpenSSL is allowed.
46 50
 
47 51
  See doc/COPYING for details.
48 52
 
... ...
@@ -50,21 +54,24 @@ Applications:
50 54
 
51 55
  The following applications are shipped with SEMS :
52 56
 
57
+ Announcements (Prompts, Ringbacktones, Pre-call-prompts):
53 58
   * announcement   plays an announcement
54 59
 
55
-  * voicemail      records voice messages and sends them 
56
-                   as email, saves them to a voicebox, or
57
-                   both
58 60
 
59
-  * conference     enables many people to talk together 
60
-                   at the same time
61
+  * ann_b2b        pre-call-announcement, plays announcement 
62
+                   before connecting the callee in B2BUA mode
63
+ 
64
+  * announce_transfer  pre-call-announcement, plays announcement 
65
+                   and then transfers the caller to the callee 
66
+                   using REFER
61 67
 
62
-  * webconference  conference application that can be 
63
-                   controlled from an external program, 
64
-                   e.g. a website 
68
+  * early_announce (pre-call) announcement using early media (183),
69
+                   optionally continues the call in B2BUA mode
65 70
 
66
-  * echo           test module to echo the caller's voice
67
- 
71
+  * precoded_announce plays preencoded announcements
72
+
73
+
74
+ Voicemail/Mailbox
68 75
   * voicebox       users can dial in to the voicebox to check
69 76
                    their messages
70 77
 
... ...
@@ -75,18 +82,19 @@ Applications:
75 82
                    an IMAP server. Users can dial in to check
76 83
                    their messages (simpler version)
77 84
 
78
-  * ann_b2b        pre-call-announcement, plays announcement 
79
-                   before connecting the callee in B2BUA mode
80
- 
81
-  * announce_transfer  pre-call-announcement, plays announcement 
82
-                   and then transfers the caller to the callee 
83
-                   using REFER
85
+  * voicemail      records voice messages and sends them 
86
+                   as email, saves them to a voicebox, or
87
+                   both
84 88
 
85
-  * early_announce (pre-call) announcement using early media (183),
86
-                   optionally continues the call in B2BUA mode
87 89
 
88
-  * auth_b2b       B2BUA app that changes identity and authenticates
89
-                   second call leg
90
+ Conferencing
91
+
92
+  * conference     enables many people to talk together 
93
+                   at the same time
94
+
95
+  * webconference  conference application that can be 
96
+                   controlled from an external program, 
97
+                   e.g. a website 
90 98
 
91 99
   * conf_auth      collect a PIN number, verify it against an 
92 100
                    XMLRPC authentication server and connects in 
... ...
@@ -95,18 +103,33 @@ Applications:
95 103
   * pin_collect    collect a PIN, optionally verify it, and transfer
96 104
                    the call into a conference
97 105
 
106
+ Back-to-back User Agent
107
+  
108
+  * sbc            flexible SBC application, supports
109
+                    - identity change
110
+                    - header manipulation (filter etc)
111
+                    - (multihomed) RTP relay
112
+                    - SIP authentication 
113
+                    - Session timer, call timer, prepaid
114
+                    etc
115
+ App development
116
+
117
+  * dsm            DSM state machine scripting (use this)
118
+
119
+  * ivr            embedded Python interpreter for simple apps
120
+  
121
+  * py_sems        another embedded Python interpreter
122
+
123
+ Misc
124
+  * echo           test module to echo the caller's voice
125
+ 
126
+
98 127
   * callback       reject the call, call back caller later and have 
99 128
                    her enter a number to call in b2bua with media relay
100 129
                    mode
101 130
 
102 131
   * reg_agent     SIP REGISTER to register SEMS' contact to an aor
103 132
 
104
-  * sw_prepaid_sip prepaid application
105
-  
106
-  * call_timer     B2BUA, ends the call after a certain time
107
-
108
-  * precoded_announce plays preencoded announcements
109
-
110 133
 
111 134
 Developing and customizing Applications and services:
112 135
 
... ...
@@ -141,22 +164,14 @@ Requirements:
141 164
 
142 165
  All requirements are optional.
143 166
 
144
- 1. Python version >= 2.3 for the ivr (embedded python interpreter)
145
-    and py_sems, optional
146
-
147
- 2. flite speech synthesizer for TTS in the ivr, optional
148
-
149
- 3. lame >= 3.95 for mp3 file output, optional. mpg123 for mp3 playback,
150
-    optional
151
-
152
- 4. xmlrpcpp for XMLRPC control, optional
153
-
154
- 5. spandsp library for DTMF detection and PLC, optional
167
+ o Python version >= 2.3 for the ivr (embedded python interpreter)
168
+    and py_sems
169
+ o flite speech synthesizer for TTS in the ivr
170
+ o lame >= 3.95 for mp3 file output, mpg123 for mp3 playback
171
+ o spandsp library for DTMF detection and PLC
155 172
     (SEMS has its own implementations for both)
156
-
157
- 6. libZRTP SDK (http://zfoneproject.com) for ZRTP, optional
158
-
159
- 7. libev for jsonrpc, optional
173
+ o libZRTP SDK (http://zfoneproject.com) for ZRTP
174
+ o libev for jsonrpc
160 175
 
161 176
 How to get started with SEMS:
162 177
 
... ...
@@ -164,85 +179,41 @@ How to get started with SEMS:
164 179
   http://ftp.iptel.org/pub/sems/, unpack and install it 
165 180
   using the usual make && make install. After installation, the 
166 181
   configuration file /usr/local/etc/sems/sems.conf needs to be 
167
-  adapted.
182
+  adapted, especially the parameters "sip_ip", "media_ip",
183
+  "load_plugins", "application".
168 184
 
169
-  On debian, you can add the iptel.org SEMS repository to 
185
+  On Debian and Ubuntu, add the SEMS repository from OBS to 
170 186
   /etc/apt/sources.list:
171
-   deb http://ftp.iptel.org/pub/sems/debian lenny free
172
-   deb-src http://ftp.iptel.org/pub/sems/debian lenny free
173
-  and install SEMS from binary packages with: 
174
-  $ apt-get install sems sems-python-modules
175
-  If you want to build SEMS from source on debian, see below.
176
-
177
-  On Fedora, simply do 
187
+     deb http://download.opensuse.org/repositories/home:/team-sems/Debian_5.0 ./
188
+  and install SEMS packages with: 
189
+   wget http://download.opensuse.org/repositories/home:/team-sems/Debian_5.0/Release.key \
190
+        -O - |apt-key add -   
191
+   apt-get update && apt-get install sems
192
+  If you want to build SEMS from source on debian/derivatives, see below.
193
+
194
+  On Fedora/CentOS, simply do 
178 195
    $ sudo yum install sems
179 196
   and sems package will be installed.
180 197
  
181
-  You can also follow one of the tutorials
182
-  linked from the SEMS homepage
183
-  (e.g. http://www.iptel.org/howto_sems_voicemail).The Application
184
-  Modules Documentation page then gives an overview of the application
185
-  modules that come with SEMS 
198
+  You can also follow one of the tutorials linked from the SEMS homepage
199
+  (e.g. http://ftp.iptel.org/pub/sems/doc/current/howtostart_noproxy.html).
200
+  The Application Modules Documentation page then gives an 
201
+  overview of the application modules that come with SEMS 
186 202
   (http://ftp.iptel.org/pub/sems/doc/current/AppDoc.html).
187 203
   
188 204
   If you are interested in writing your own applications, the 
189 205
   application development tutorial is a good start 
190 206
   (http://www.iptel.org/sems/sems_application_development_tutorial),
191
-  together  with the design overview 
207
+  together with the design overview 
192 208
   (http://www.iptel.org/files/semsng-designoverview.pdf) and the example
193 209
   applications (apps/examples/).
194
-  
195
-Installation:
196
-
197
- 1. Download SEMS 
198
-     Download the source tarball from ftp://ftp.iptel.org/pub/sems/,
199
-     or get the newest version through svn:
200
-      $ svn checkout svn://svn.berlios.de/sems/trunk
201
-       -or-
202
-      $ svn checkout http://svn.berlios.de/svnroot/repos/sems/trunk 
203
-
204
- 2. Compile SEMS
205
-
206
-      $ make all
207
-      $ make install
208
-
209
-    Notice: you don't need to execute 'make install' if you want to 
210
-            run SEMS from the source tree, but in this case some paths 
211
-            in the config files will need to be adapted.
212
-            If you want to install to a different prefix than /usr/local,
213
-            use PREFIX=/some/other/prefix 
214
-     
215
-    For detailed instructions for some modules, have a look at
216
-    doc/COMPILING as well.
217
-
218
- 3. Look at the default configuration file whether it fits your need:
219
-
220
-    If you installed SEMS with 'make install', the configuration
221
-    is at '/usr/local/etc/sems/sems.conf'. 
222
-    Else make your own using sems.conf.sample.
223
-
224
- 4. Start SEMS:
225
-
226
-    If you installed SEMS with 'make install', sems can be
227
-    found at '/usr/local/sbin/sems'.
228
-    If you need help starting 'sems', try 'sems -h'.
229
-
230
- 5. Using SEMS
231
-    
232
-    SEMS needs to be told from the many possible applications that are
233
-    loaded which one to run. You can simply set the application 
234
-    in sems.conf, e.g. application=conference. You can also define an
235
-    application mapping, i.e. numbers (R-URIs) that will be mapped to
236
-    applications, see the explanation of 'application' parameter in 
237
-    sems.conf.
238 210
    
239
-    Alternatively, the SIP-stack-SER can be configured in ser-sems.cfg
240
-    to send all calls directly to one application, in that case the line
241
-     if(!t_write_unix("/tmp/sems_sock","sems/app_headers"))
242
-    in ser-sems.cfg could be changed to e.g.
243
-     if(!t_write_unix("/tmp/sems_sock","conference"))
244
-    A sample ser.cfg file in this style can be found at 
245
-    http://ftp.iptel.org/pub/sems/ser.cfg
211
+  SEMS needs to be told from the many possible applications that are
212
+  loaded which one to run. You can simply set the application 
213
+  in sems.conf, e.g. application=conference. You can also define an
214
+  application mapping, i.e. numbers (R-URIs) that will be mapped to
215
+  applications, see the explanation of 'application' parameter in 
216
+  sems.conf.
246 217
 
247 218
 Creating packages on debian (ubuntu, ...):
248 219
 
... ...
@@ -316,6 +287,7 @@ Authors:
316 287
     Andreas Granig
317 288
     Andrey Samusenko
318 289
     Andriy I Pylypenko
290
+    Anton Zagorskiy
319 291
     B. Oldenburg
320 292
     Balint Kovacs
321 293
     Bogdan Pintea
... ...
@@ -325,6 +297,7 @@ Authors:
325 297
     Jeremy A
326 298
     Jiri Kuthan
327 299
     Juha Heinanen
300
+    Matthew Williams
328 301
     Ovidiu Sas
329 302
     Peter Lemenkov
330 303
     Peter Loeppky
... ...
@@ -333,9 +306,10 @@ Authors:
333 306
     Rui Jin Zheng
334 307
     Tom van der Geer
335 308
     Ulrich Abend
336
-   (if you want to be added or removed from this list, please mail to stefan.sayer@gmail.com)
309
+   (if you feel you should be on this list, please mail to stefan.sayer@gmail.com)
337 310
  
338
-  Special thanks to IPTEGO GmbH and iptelorg GmbH for sponsoring development of SEMS.
311
+  Special thanks to IPTEGO GmbH, iptelorg GmbH and TelTech Systems Inc. for 
312
+  sponsoring development of SEMS.
339 313
 
340 314
 Contributions:
341 315
 
... ...
@@ -1,10 +1,12 @@
1
-#CFGOPTION_SEMS_ANNOUNCEPATH
1
+# File to be played:
2
+#  1) [announce_path]/[Domain]/[User].wav
3
+#  2) [announce_path]/[User].wav
4
+#  3) [announce_path]/[default_announce]
5
+# first found is played
6
+
2 7
 announce_path=/usr/local/lib/sems/audio/
3
-#ENDCFGOPTION
4 8
 
5
-#CFGOPTION_SEMS_ANNOUNCEMENT
6 9
 default_announce=default_en.wav
7
-#ENDCFGOPTION
8 10
 
9 11
 # optional parameter: loop
10 12
 #  set to "true" to make the announcement loop
... ...
@@ -50,6 +50,10 @@ playout_type=adaptive_playout
50 50
 #
51 51
 # minimum_timer=90
52 52
 
53
+# -  maximum Timer value we want to accept
54
+#
55
+#maximum_timer=900
56
+
53 57
 # session refresh (Session Timer, RFC4028) method
54 58
 #
55 59
 # INVITE                 - use re-INVITE
... ...
@@ -398,11 +398,11 @@ char*  AAAConvertAVPToString(AAA_AVP *avp, char *dest, unsigned int destLen)
398 398
 
399 399
     switch(avp->type) {
400 400
     case AAA_AVP_STRING_TYPE:
401
-      l+=snprintf(dest+l,destLen-l,"String: <%.*s>",avp->data.len,
401
+      /*l+=*/snprintf(dest+l,destLen-l,"String: <%.*s>",avp->data.len,
402 402
 		  avp->data.s);
403 403
       break;
404 404
     case AAA_AVP_INTEGER32_TYPE:
405
-      l+=snprintf(dest+l,destLen-l,"Int32: <%u>(%x)",
405
+      /*l+=*/snprintf(dest+l,destLen-l,"Int32: <%u>(%x)",
406 406
 		  (unsigned int)htonl(*((unsigned int*)avp->data.s)),
407 407
 		  (unsigned int)htonl(*((unsigned int*)avp->data.s)));
408 408
       break;
... ...
@@ -411,7 +411,7 @@ char*  AAAConvertAVPToString(AAA_AVP *avp, char *dest, unsigned int destLen)
411 411
       switch (avp->data.len) {
412 412
       case 4: i=i*0;
413 413
       case 6: i=i*2;
414
-	l+=snprintf(dest+l,destLen-l,"Address IPv4: <%d.%d.%d.%d>",
414
+	/*l+=*/snprintf(dest+l,destLen-l,"Address IPv4: <%d.%d.%d.%d>",
415 415
 		    (unsigned char)avp->data.s[i+0],
416 416
 		    (unsigned char)avp->data.s[i+1],
417 417
 		    (unsigned char)avp->data.s[i+2],
... ...
@@ -419,7 +419,7 @@ char*  AAAConvertAVPToString(AAA_AVP *avp, char *dest, unsigned int destLen)
419 419
 	break;
420 420
       case 16: i=i*0;
421 421
       case 18: i=i*2;
422
-	l+=snprintf(dest+l,destLen-l,
422
+	/*l+=*/snprintf(dest+l,destLen-l,
423 423
 		    "Address IPv6: <%x.%x.%x.%x.%x.%x.%x.%x>",
424 424
 		    ((avp->data.s[i+0]<<8)+avp->data.s[i+1]),
425 425
 		    ((avp->data.s[i+2]<<8)+avp->data.s[i+3]),
... ...
@@ -44,14 +44,6 @@ SCStrArgAction::SCStrArgAction(const string& m_arg) {
44 44
     arg = trim(arg, "'");
45 45
 }
46 46
 
47
-string trim(string const& str,char const* sepSet)
48
-{
49
-  string::size_type const first = str.find_first_not_of(sepSet);
50
-  return ( first==string::npos )
51
-    ? std::string()  : 
52
-    str.substr(first, str.find_last_not_of(sepSet)-first+1);
53
-}
54
-
55 47
 bool isNumber(const std::string& s) {
56 48
   if (s.empty())
57 49
     return false;
... ...
@@ -81,9 +81,6 @@ typedef void* (*SCFactoryCreate)();
81 81
 #define SC_EXPORT(class_name)			\
82 82
   EXPORT_SC_FACTORY(SC_FACTORY_EXPORT,class_name)
83 83
 
84
-
85
-string trim(string const& str,char const* sepSet);
86
-
87 84
 class SCStrArgAction   
88 85
 : public DSMAction {
89 86
  protected:
... ...
@@ -92,7 +92,7 @@ typedef map<string, string> VarMapT;
92 92
 typedef map<string, AmArg>  AVarMapT;
93 93
 
94 94
 class DSMDisposable;
95
-class AmPlaylistItem;
95
+struct AmPlaylistItem;
96 96
 
97 97
 class DSMSession {
98 98
 
... ...
@@ -282,13 +282,13 @@ EXEC_ACTION_START(DLGDialoutAction) {
282 282
  
283 283
   DBG("sess_params: '%s'\n", AmArg::print(*sess_params).c_str());
284 284
 
285
-  AmSession* new_sess = AmUAC::dialout(user, app_name, r_uri, from, from_uri, to, ltag, hdrs, sess_params);
286
-
287
- if (NULL != new_sess) {
288
-   sc_sess->var[arrayname + "_ltag"] = new_sess->getLocalTag();
289
- } else {
290
-   sc_sess->var[arrayname + "_ltag"] = "";
291
-   sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
292
- }
285
+  string new_sess_tag = AmUAC::dialout(user, app_name, r_uri, from, from_uri, to, ltag, hdrs, sess_params);
286
+
287
+  if (!new_sess_tag.empty()) {
288
+    sc_sess->var[arrayname + "_ltag"] = new_sess_tag;
289
+  } else {
290
+    sc_sess->var[arrayname + "_ltag"] = "";
291
+    sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
292
+  }
293 293
 
294 294
 } EXEC_ACTION_END;
... ...
@@ -312,10 +312,10 @@ EXEC_ACTION_START(SCSysGetTimestampAction) {
312 312
   // long unsigned msecs = tv.tv_sec * 1000 + tv.tv_usec / 1000;
313 313
 
314 314
   char ms_buf[40];
315
-  snprintf(ms_buf, 40, "%lu", tv.tv_sec);
315
+  snprintf(ms_buf, 40, "%li", tv.tv_sec);
316 316
   sc_sess->var[varname+".tv_sec"] = ms_buf;
317 317
 
318
-  snprintf(ms_buf, 40, "%lu", (long unsigned int)tv.tv_usec);
318
+  snprintf(ms_buf, 40, "%li", (long int)tv.tv_usec);
319 319
   sc_sess->var[varname+".tv_usec"] = ms_buf;
320 320
 
321 321
   DBG("got timestamp $%s=%s, $%s=%s, \n",
... ...
@@ -343,10 +343,10 @@ EXEC_ACTION_START(SCSysSubTimestampAction) {
343 343
   timersub(&tv1,&tv2,&diff);
344 344
 
345 345
   char ms_buf[40];
346
-  snprintf(ms_buf, 40, "%lu", diff.tv_sec);
346
+  snprintf(ms_buf, 40, "%li", diff.tv_sec);
347 347
   sc_sess->var[t1+".tv_sec"] = ms_buf;
348 348
 
349
-  snprintf(ms_buf, 40, "%lu", (long unsigned int)diff.tv_usec);
349
+  snprintf(ms_buf, 40, "%li", (long int)diff.tv_usec);
350 350
   sc_sess->var[t1+".tv_usec"] = ms_buf;
351 351
 
352 352
   // may be overflowing - use only if timestamps known
... ...
@@ -262,7 +262,7 @@ EXEC_ACTION_START(SCUPlayRingToneAction) {
262 262
     if (p.empty())
263 263
       continue;
264 264
     if (!str2int(p, rtparams[it-r_params.begin()])) {
265
-      WARN("could not decipher ringtone parameter %u: '%s', using default\n",
265
+      WARN("could not decipher ringtone parameter %zd: '%s', using default\n",
266 266
 	   it-r_params.begin(), p.c_str());
267 267
       continue;
268 268
     }
... ...
@@ -255,7 +255,7 @@ void CallGenFactory::createCall(const AmArg& args) {
255 255
   AmArg* c_args = new AmArg(args);
256 256
   
257 257
   DBG("placing new call to %s\n", call_ruri.c_str());
258
-  /* AmSession* s = */ AmUAC::dialout("callgen", // user
258
+  /* string tag = */ AmUAC::dialout("callgen", // user
259 259
 				APP_NAME,  
260 260
 				call_ruri,
261 261
 				"<" + from +  ">", from, 
... ...
@@ -132,11 +132,11 @@ string DIDial::dialout(const string& application,
132 132
   DBG("dialout application '%s', user '%s', from '%s', to '%s'\n", 
133 133
       application.c_str(), user.c_str(), from.c_str(), to.c_str());
134 134
 
135
-  AmSession* s = AmUAC::dialout(user.c_str(), application,  to,  
135
+  string tag = AmUAC::dialout(user.c_str(), application,  to,  
136 136
 				"<" + from +  ">", from, "<" + to + ">", 
137 137
 				string(""), string(""), extra_params);
138
-  if (s)
139
-    return s->getLocalTag();
138
+  if (!tag.empty())
139
+    return tag;
140 140
   else 
141 141
     return "<failed>";  
142 142
 }
... ...
@@ -162,15 +162,15 @@ string DIDial::dialout_auth(const string& application,
162 162
   } else {
163 163
     a->setBorrowedPointer(new UACAuthCred(a_realm, a_user, a_pwd));
164 164
   }
165
-  AmSession* s = AmUAC::dialout(user.c_str(), application,  to,  
165
+  string tag = AmUAC::dialout(user.c_str(), application,  to,  
166 166
 				"<" + from +  ">", from, "<" + to + ">", 
167 167
 				string(""), // callid
168 168
 				string(""), // xtra hdrs
169 169
 				a);
170 170
   delete a;
171 171
 
172
-  if (s)
173
-    return s->getLocalTag();
172
+  if (!tag.empty())
173
+    return tag;
174 174
   else 
175 175
     return "<failed>\n";
176 176
 }
... ...
@@ -195,14 +195,14 @@ string DIDial::dialout_auth_b2b(const string& application,
195 195
   a.push(a_pwd.c_str());
196 196
   a.push(callee_ruri.c_str());
197 197
 
198
-  AmSession* s = AmUAC::dialout(
198
+  string tag = AmUAC::dialout(
199 199
       announcement.c_str(), application,  caller_ruri,
200 200
       "<" + from +  ">", from, "<" + to + ">", 
201 201
       string(""), // callid
202 202
       string(""), //xtra hdrs
203 203
       &a);
204
-  if (s)
205
-    return s->getLocalTag();
204
+  if (!tag.empty())
205
+    return tag;
206 206
   else 
207 207
     return "<failed>\n";
208 208
 }
... ...
@@ -223,7 +223,7 @@ string DIDial::dialout_pin(const string& application,
223 223
 					  it->second.user, 
224 224
 					  it->second.pwd));
225 225
     
226
-    AmSession* s = AmUAC::dialout(user.c_str(), application,  
226
+    string tag = AmUAC::dialout(user.c_str(), application,  
227 227
 				  "sip:"+to_user+"@"+it->second.realm,  
228 228
 				  "<sip:" + it->second.user+"@"+it->second.realm + ">", 
229 229
 				  "sip:"+it->second.user+"@"+it->second.realm, 
... ...
@@ -231,8 +231,8 @@ string DIDial::dialout_pin(const string& application,
231 231
 				  string(""), // callid
232 232
 				  string(""), // xtra hdrs
233 233
 				  a);
234
-    if (s)
235
-      return s->getLocalTag();
234
+    if (!tag.empty())
235
+      return tag;
236 236
     else 
237 237
       return "<failed>\n";
238 238
   } else 
... ...
@@ -49,7 +49,6 @@ static PyObject* IvrUAC_dialout(IvrUAC* self, PyObject* args)
49 49
 		       &from, &from_uri, &to))
50 50
     return NULL;
51 51
 
52
-  //AmSession* newSession = 
53 52
   AmUAC::dialout(user, app_name, r_uri, 
54 53
 		 from, from_uri, to);
55 54
 
... ...
@@ -18,6 +18,10 @@ script_path=/usr/local/lib/sems/ivr/
18 18
 #
19 19
 # minimum_timer=90
20 20
 
21
+# -  maximum Timer value we want to accept
22
+#
23
+#maximum_timer=900
24
+
21 25
 # session refresh (Session Timer, RFC4028) method
22 26
 #
23 27
 # INVITE                 - use re-INVITE
... ...
@@ -43,6 +43,7 @@ using std::string;
43 43
 #include "AmUtils.h"
44 44
 #include "AmEventDispatcher.h"
45 45
 #include "JsonRPCEvents.h"
46
+#include "sip/resolver.h"
46 47
 
47 48
 void JsonrpcPeerConnection::notifyDisconnect() {
48 49
   // let event receivers know about broken connection
... ...
@@ -73,13 +74,27 @@ JsonrpcNetstringsConnection::JsonrpcNetstringsConnection(const std::string& id)
73 74
 JsonrpcNetstringsConnection::~JsonrpcNetstringsConnection() {
74 75
 }
75 76
 
76
-int JsonrpcNetstringsConnection::connect(const string& host, int port, string& res_str) {  
77
+int JsonrpcNetstringsConnection::connect(const string& host, int port,
78
+					 string& res_str) {
77 79
   struct sockaddr_in sa;
78
-  if (!populate_sockaddr_in_from_name(host, &sa)) {
79
-    res_str = "populate_sockaddr_in_from_name failed\n";
80
-    return 300;
80
+  {
81
+    sockaddr_storage _sa;
82
+    dns_handle       _dh;
83
+
84
+    if(resolver::instance()->resolve_name(host.c_str(),
85
+					&_dh,&_sa,IPv4) < 0) {
86
+      res_str = "resolving '"+host+"' failed\n";
87
+      return 300;
88
+    }
89
+
90
+    memcpy(&sa.sin_addr,&((sockaddr_in*)&_sa)->sin_addr,sizeof(in_addr));
81 91
   }
82 92
 
93
+  // if (!populate_sockaddr_in_from_name(host, &sa)) {
94
+  //   res_str = "populate_sockaddr_in_from_name failed\n";
95
+  //   return 300;
96
+  // }
97
+
83 98
   fd = socket(PF_INET, SOCK_STREAM, 0);
84 99
   sa.sin_port = htons(port);
85 100
   sa.sin_family = PF_INET;
... ...
@@ -11,4 +11,4 @@
11 11
 # run garbage collection every n seconds
12 12
 # Default: 10
13 13
 #
14
-#garbage_collector_interval = 20
15 14
\ No newline at end of file
15
+#garbage_collector_interval = 20
... ...
@@ -11,4 +11,4 @@
11 11
 # run garbage collection every n seconds
12 12
 # Default: 10
13 13
 #
14
-#garbage_collector_interval = 20
15 14
\ No newline at end of file
15
+#garbage_collector_interval = 20
... ...
@@ -5,4 +5,4 @@
5 5
 #
6 6
 # default: /var/spool/voicebox/
7 7
 #
8
-#storage_dir=/var/spool/voicebox/
9 8
\ No newline at end of file
9
+#storage_dir=/var/spool/voicebox/
... ...
@@ -5,4 +5,4 @@
5 5
 #
6 6
 # default: /var/spool/voicebox/
7 7
 #
8
-#storage_dir=/var/spool/voicebox/
9 8
\ No newline at end of file
9
+#storage_dir=/var/spool/voicebox/
... ...
@@ -4,13 +4,16 @@
4 4
 # refreshed if necessary.
5 5
 #
6 6
 #
7
+# See also proxy_sticky_auth configuration in sems.conf
8
+# for some (broken) registrars.
7 9
 
8 10
 #domain=mydomain.net
9 11
 #user=myuser
12
+#pwd=verysecret
13
+# optional (defaults to user):
10 14
 #display_name=myuser
11 15
 #auth_user=myuser
12
-#pwd=verysecret
13
-# optional:
16
+# optional (defaults to resolved by domain):
14 17
 #proxy=sip.mydomain.net:5060
15 18
 
16 19
 #
... ...
@@ -18,17 +21,17 @@
18 21
 #
19 22
 #domain1=iptel.org
20 23
 #user1=xyz
21
-#display_name1=xyz
22
-#auth_user1=xyz
23 24
 #pwd1=ppp
24 25
 # optional:
26
+#display_name1=xyz
27
+#auth_user1=xyz
25 28
 #proxy1=sip.iptel.org:5060
26 29
 
27 30
 #domain2=iptel.org
28 31
 #user2=xyz
29
-#display_name2=xyz
30
-#auth_user2=xyz
31 32
 #pwd2=ppp
32 33
 # optional:
34
+#display_name2=xyz
35
+#auth_user2=xyz
33 36
 #proxy2=sip.iptel.org:5060
34 37
 
... ...
@@ -4,13 +4,16 @@
4 4
 # refreshed if necessary.
5 5
 #
6 6
 #
7
+# See also proxy_sticky_auth configuration in sems.conf
8
+# for some (broken) registrars.
7 9
 
8 10
 #domain=mydomain.net
9 11
 #user=myuser
12
+#pwd=verysecret
13
+# optional (defaults to user):
10 14
 #display_name=myuser
11 15
 #auth_user=myuser
12
-#pwd=verysecret
13
-# optional:
16
+# optional (defaults to resolved by domain):
14 17
 #proxy=sip.mydomain.net:5060
15 18
 
16 19
 #
... ...
@@ -18,17 +21,17 @@
18 21
 #
19 22
 #domain1=iptel.org
20 23
 #user1=xyz
21
-#display_name1=xyz
22
-#auth_user1=xyz
23 24
 #pwd1=ppp
24 25
 # optional:
26
+#display_name1=xyz
27
+#auth_user1=xyz
25 28
 #proxy1=sip.iptel.org:5060
26 29
 
27 30
 #domain2=iptel.org
28 31
 #user2=xyz
29
-#display_name2=xyz
30
-#auth_user2=xyz
31 32
 #pwd2=ppp
32 33
 # optional:
34
+#display_name2=xyz
35
+#auth_user2=xyz
33 36
 #proxy2=sip.iptel.org:5060
34 37
 
... ...
@@ -155,7 +155,7 @@ class SIPRegistration : //public AmSipDialogEventHandler,
155 155
   const string& getEventSink() { return sess_link; }
156 156
 };
157 157
 
158
-class SIPNewRegistrationEvent;
158
+struct SIPNewRegistrationEvent;
159 159
 class SIPRemoveRegistrationEvent;
160 160
 
161 161
 class SIPRegistrarClient  : public AmThread,
... ...
@@ -18,6 +18,7 @@ sbc
18 18
 src_ipmap
19 19
 sst_b2b.sbcprofile
20 20
 transparent.sbcprofile
21
+symmetricrtp.sbcprofile
21 22
 )
22 23
 
23 24
 INSTALL(PROGRAMS
... ...
@@ -26,7 +26,6 @@
26 26
 /* 
27 27
 SBC - feature-wishlist
28 28
 - accounting (MySQL DB, cassandra DB)
29
-- RTP forwarding mode (bridging)
30 29
 - RTP transcoding mode (bridging)
31 30
 - overload handling (parallel call to target thresholds)
32 31
 - call distribution
... ...
@@ -482,7 +481,8 @@ void SBCFactory::setRegexMap(const AmArg& args, AmArg& ret) {
482 481
 SBCDialog::SBCDialog(const SBCCallProfile& call_profile)
483 482
   : m_state(BB_Init),
484 483
     prepaid_acc(NULL),
485
-    call_profile(call_profile)
484
+    call_profile(call_profile),
485
+    outbound_interface(-1)
486 486
 {
487 487
   set_sip_relay_only(false);
488 488
   dlg.reliable_1xx = REL100_IGNORED;
... ...
@@ -547,9 +547,43 @@ void SBCDialog::onInvite(const AmSipRequest& req)
547 547
     }
548 548
   }
549 549
 
550
+  if (call_profile.rtprelay_enabled) {
551
+    DBG("Enabling RTP relay mode for SBC call\n");
552
+
553
+    // force symmetric RTP?
554
+    if (!call_profile.force_symmetric_rtp.empty()) {
555
+      string force_symmetric_rtp =
556
+	replaceParameters(call_profile.force_symmetric_rtp, "force_symmetric_rtp",
557
+			  REPLACE_VALS);
558
+      if (!force_symmetric_rtp.empty() && force_symmetric_rtp != "no"
559
+	  && force_symmetric_rtp != "0") {
560
+	DBG("forcing symmetric RTP (passive mode)\n");
561
+	rtp_relay_force_symmetric_rtp = true;
562
+      }
563
+    }
564
+    // enable symmetric RTP by P-MsgFlags?
565
+    if (!rtp_relay_force_symmetric_rtp) {
566
+      if (call_profile.msgflags_symmetric_rtp) {
567
+	string str_msg_flags = getHeader(req.hdrs,"P-MsgFlags", true);
568
+	unsigned int msg_flags = 0;
569
+	if(reverse_hex2int(str_msg_flags,msg_flags)){
570
+	  ERROR("while parsing 'P-MsgFlags' header\n");
571
+	  msg_flags = 0;
572
+	}
573
+	if (msg_flags & FL_FORCE_ACTIVE) {
574
+	  DBG("P-MsgFlags indicates forced symmetric RTP (passive mode)");
575
+	  rtp_relay_force_symmetric_rtp = true;
576
+	}
577
+      }
578
+    }
579
+
580
+    enableRtpRelay(req);
581
+  }
582
+
550 583
   m_state = BB_Dialing;
551 584
 
552 585
   invite_req = req;
586
+  est_invite_cseq = req.cseq;
553 587
 
554 588
   removeHeader(invite_req.hdrs,PARAM_HDR);
555 589
   removeHeader(invite_req.hdrs,"P-App-Name");
... ...
@@ -583,6 +617,30 @@ void SBCDialog::onInvite(const AmSipRequest& req)
583 617
       replaceParameters(call_profile.auth_credentials.pwd, "auth_pwd", REPLACE_VALS);
584 618
   }
585 619
 
620
+  if (!call_profile.outbound_interface.empty()) {
621
+    call_profile.outbound_interface = 
622
+      replaceParameters(call_profile.outbound_interface, "outbound_interface",
623
+			REPLACE_VALS);
624
+
625
+    if (!call_profile.outbound_interface.empty()) {
626
+      if (call_profile.outbound_interface == "default")
627
+	outbound_interface = 0;
628
+      else {
629
+	map<string,unsigned short>::iterator name_it =
630
+	  AmConfig::If_names.find(call_profile.outbound_interface);
631
+	if (name_it != AmConfig::If_names.end()) {
632
+	  outbound_interface = name_it->second;
633
+	} else {
634
+	  ERROR("selected outbound_interface '%s' does not exist as an interface. "
635
+		"Please check the 'additional_interfaces' "
636
+		"parameter in the main configuration file.",
637
+		call_profile.outbound_interface.c_str());
638
+	  throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
639
+	}
640
+      }
641
+    }
642
+  }
643
+
586 644
   // get timer
587 645
   if (call_profile.call_timer_enabled || call_profile.prepaid_enabled) {
588 646
     if (!timersSupported()) {
... ...
@@ -971,9 +1029,9 @@ void SBCDialog::createCalleeSession()
971 1029
 
972 1030
   AmSipDialog& callee_dlg = callee_session->dlg;
973 1031
 
974
-  callee_dlg.force_outbound_proxy = call_profile.force_outbound_proxy;
975 1032
   if (!call_profile.outbound_proxy.empty()) {
976 1033
     callee_dlg.outbound_proxy = call_profile.outbound_proxy;
1034
+    callee_dlg.force_outbound_proxy = call_profile.force_outbound_proxy;
977 1035
   }
978 1036
   
979 1037
   if (!call_profile.next_hop_ip.empty()) {
... ...
@@ -988,6 +1046,9 @@ void SBCDialog::createCalleeSession()
988 1046
     }
989 1047
   }
990 1048
 
1049
+  if(outbound_interface >= 0)
1050
+    callee_dlg.outbound_interface = outbound_interface;
1051
+
991 1052
   other_id = AmSession::getNewId();
992 1053
   
993 1054
   callee_dlg.local_tag    = other_id;
... ...
@@ -1015,6 +1076,14 @@ void SBCDialog::createCalleeSession()
1015 1076
 		  "to",   callee_dlg.remote_party.c_str(),
1016 1077
 		  "ruri", callee_dlg.remote_uri.c_str());
1017 1078
 
1079
+  try {
1080
+    initializeRTPRelay(callee_session);
1081
+  }
1082
+  catch (...) {
1083
+    delete callee_session;
1084
+    throw;
1085
+  }
1086
+
1018 1087
   callee_session->start();
1019 1088
   
1020 1089
   AmSessionContainer* sess_cont = AmSessionContainer::instance();
... ...
@@ -106,6 +106,8 @@ class SBCDialog : public AmB2BCallerSession
106 106
 
107 107
   unsigned int call_timer;
108 108
 
109
+  int outbound_interface;
110
+
109 111
   // prepaid
110 112
   AmDynInvoke* prepaid_acc;
111 113
   time_t prepaid_starttime;
... ...
@@ -30,7 +30,7 @@
30 30
 #include "log.h"
31 31
 #include "AmUtils.h"
32 32
 #include "AmPlugIn.h"
33
-
33
+#include "AmConfig.h"
34 34
 
35 35
 bool SBCCallProfile::readFromConfiguration(const string& name,
36 36
 					   const string profile_file_name) {
... ...
@@ -173,6 +173,12 @@ bool SBCCallProfile::readFromConfiguration(const string& name,
173 173
 
174 174
   refuse_with = cfg.getParameter("refuse_with");
175 175
 
176
+  rtprelay_enabled = cfg.getParameter("enable_rtprelay") == "yes";
177
+  force_symmetric_rtp = cfg.getParameter("rtprelay_force_symmetric_rtp");
178
+  msgflags_symmetric_rtp = cfg.getParameter("rtprelay_msgflags_symmetric_rtp") == "yes";
179
+
180
+  outbound_interface = cfg.getParameter("outbound_interface");
181
+
176 182
   md5hash = "<unknown>";
177 183
   if (!cfg.getMD5(profile_file_name, md5hash)){
178 184
     ERROR("calculating MD5 of file %s\n", profile_file_name.c_str());
... ...
@@ -209,6 +215,17 @@ bool SBCCallProfile::readFromConfiguration(const string& name,
209 215
 	 sdpfilter_enabled?"en":"dis", FilterType2String(sdpfilter),
210 216
 	 sdpfilter_list.size());
211 217
 
218
+    INFO("SBC:      RTP relay %sabled\n", rtprelay_enabled?"en":"dis");
219
+    if (rtprelay_enabled) {
220
+      if (!force_symmetric_rtp.empty()) {
221
+	INFO("SBC:      RTP force symmetric RTP: %s\n",
222
+	     force_symmetric_rtp.c_str());
223
+      }
224
+      if (msgflags_symmetric_rtp) {
225
+	INFO("SBC:      P-MsgFlags symmetric RTP detection enabled\n");
226
+      }
227
+    }
228
+
212 229
     INFO("SBC:      SST %sabled\n", sst_enabled?"en":"dis");
213 230
     INFO("SBC:      SIP auth %sabled\n", auth_enabled?"en":"dis");
214 231
     INFO("SBC:      call timer %sabled\n", call_timer_enabled?"en":"dis");
... ...
@@ -262,7 +279,10 @@ bool SBCCallProfile::operator==(const SBCCallProfile& rhs) const {
262 279
     prepaid_enabled == rhs.prepaid_enabled &&
263 280
     reply_translations == rhs.reply_translations &&
264 281
     append_headers == rhs.append_headers &&
265
-    refuse_with == rhs.refuse_with;
282
+    refuse_with == rhs.refuse_with &&
283
+    rtprelay_enabled == rhs.rtprelay_enabled &&
284
+    force_symmetric_rtp == rhs.force_symmetric_rtp &&
285
+    msgflags_symmetric_rtp == rhs.msgflags_symmetric_rtp;
266 286
 
267 287
   if (sdpfilter_enabled) {
268 288
     res = res &&
... ...
@@ -326,6 +346,10 @@ string SBCCallProfile::print() const {
326 346
   res += "prepaid_accmodule:    " + prepaid_accmodule + "\n";
327 347
   res += "prepaid_uuid:         " + prepaid_uuid + "\n";
328 348
   res += "prepaid_acc_dest:     " + prepaid_acc_dest + "\n";
349
+  res += "rtprelay_enabled:     " + string(rtprelay_enabled?"true":"false") + "\n";
350
+  res += "force_symmetric_rtp:  " + force_symmetric_rtp;
351
+  res += "msgflags_symmetric_rtp: " + string(msgflags_symmetric_rtp?"true":"false") + "\n";
352
+
329 353
 
330 354
   if (reply_translations.size()) {
331 355
     string reply_trans_codes;
... ...
@@ -88,7 +88,12 @@ struct SBCCallProfile {
88 88
 
89 89
   string refuse_with;
90 90
 
91
-  // todo: RTP forwarding mode
91
+  bool rtprelay_enabled;
92
+  string force_symmetric_rtp;
93
+  bool msgflags_symmetric_rtp;
94
+
95
+  string outbound_interface;
96
+
92 97
   // todo: RTP transcoding mode
93 98
 
94 99
   SBCCallProfile()
... ...
@@ -99,7 +104,9 @@ struct SBCCallProfile {
99 104
     sst_enabled(false),
100 105
     auth_enabled(false),
101 106
     call_timer_enabled(false),
102
-    prepaid_enabled(false)
107
+    prepaid_enabled(false),
108
+    rtprelay_enabled(false)
109
+
103 110
   { }
104 111
 
105 112
   ~SBCCallProfile()
... ...
@@ -58,6 +58,7 @@ prepaid_acc_dest=$H(P-Acc-Dest)
58 58
 # default values
59 59
 #session_expires=120
60 60
 #minimum_timer=90
61
+#maximum_timer=900
61 62
 #session_refresh_method=UPDATE_FALLBACK_INVITE
62 63
 #accept_501_reply=yes
63 64
 
... ...
@@ -5,4 +5,4 @@
5 5
 #
6 6
 # note: warning code 393 might not be the proper one for this usage.
7 7
 refuse_with="403 Forbidden"
8
-append_headers="Warning: 393 $rd \"Incoming calls not allowed\""
9 8
\ No newline at end of file
9
+append_headers="Warning: 393 $rd \"Incoming calls not allowed\""
... ...
@@ -5,4 +5,4 @@
5 5
 #
6 6
 # note: warning code 393 might not be the proper one for this usage.
7 7
 refuse_with="403 Forbidden"
8
-append_headers="Warning: 393 $rd \"Incoming calls not allowed\""
9 8
\ No newline at end of file
9
+append_headers="Warning: 393 $rd \"Incoming calls not allowed\""
... ...
@@ -1,2 +1,2 @@
1 1
 # swap 603 and 488 replies:
2
-reply_translations="603=>488 Not acceptable here|488=>603 Decline"
3 2
\ No newline at end of file
3
+reply_translations="603=>488 Not acceptable here|488=>603 Decline"
... ...
@@ -1,2 +1,2 @@
1 1
 # swap 603 and 488 replies:
2
-reply_translations="603=>488 Not acceptable here|488=>603 Decline"
3 2
\ No newline at end of file
3
+reply_translations="603=>488 Not acceptable here|488=>603 Decline"
... ...
@@ -47,9 +47,11 @@ enable_session_timer=yes
47 47
 # default values
48 48
 #session_expires=120
49 49
 #minimum_timer=90
50
+#maximum_timer=900
50 51
 #session_refresh_method=UPDATE_FALLBACK_INVITE
51 52
 #accept_501_reply=yes
52 53
 
54
+
53 55
 #
54 56
 #This application can be routed through for achieving 
55 57
 #two things: 
56 58
new file mode 100644
... ...
@@ -0,0 +1,21 @@
1
+# symmetricrtp SBC profile
2
+#
3
+# This implements a transparent B2BUA which relays RTP and forces
4
+# symmetric RTP on both sides - thus being able to bridge between
5
+# two NATed clients
6
+
7
+# RURI/From/To defaults: transparent
8
+#RURI=$r
9
+#From=$f
10
+#To=$t
11
+
12
+## RTP relay
13
+# enable RTP relaying (bridging):
14
+enable_rtprelay=yes
15
+# force symmetric RTP (start with passive mode):
16
+rtprelay_force_symmetric_rtp=yes
17
+# use symmetric RTP indication from P-MsgFlags flag 2
18
+#rtprelay_msgflags_symmetric_rtp=yes
19
+
20
+# outbound interface to use:
21
+#outbound_interface=extern
... ...
@@ -20,6 +20,16 @@
20 20
 #next_hop_port=5060
21 21
 # use next_hop for replies, too?
22 22
 #next_hop_for_replies=yes
23
+# outbound interface to use (interface ID)
24
+#outbound_interface=extern
25
+
26
+## RTP relay
27
+# enable RTP relaying (bridging):
28
+#enable_rtprelay=yes
29
+# force symmetric RTP (start with passive mode):
30
+#rtprelay_force_symmetric_rtp=yes
31
+# use symmetric RTP indication from P-MsgFlags flag 2
32
+#rtprelay_msgflags_symmetric_rtp=yes
23 33
 
24 34
 ## filters: 
25 35
 #header_filter=blacklist
... ...
@@ -20,6 +20,16 @@
20 20
 #next_hop_port=5060
21 21
 # use next_hop for replies, too?
22 22
 #next_hop_for_replies=yes
23
+# outbound interface to use (interface ID)
24
+#outbound_interface=extern
25
+
26
+## RTP relay
27
+# enable RTP relaying (bridging):
28
+#enable_rtprelay=yes
29
+# force symmetric RTP (start with passive mode):
30
+#rtprelay_force_symmetric_rtp=yes
31
+# use symmetric RTP indication from P-MsgFlags flag 2
32
+#rtprelay_msgflags_symmetric_rtp=yes
23 33
 
24 34
 ## filters: 
25 35
 #header_filter=blacklist
... ...
@@ -59,7 +59,7 @@ struct Attachement
59 59
 
60 60
 typedef std::vector<Attachement> Attachements;
61 61
 
62
-class AmMail;
62
+struct AmMail;
63 63
 
64 64
 /**
65 65
  * Function pointer to be called after mail processing.
... ...
@@ -32,7 +32,7 @@
32 32
 #include <string>
33 33
 using std::string;
34 34
 
35
-class AmMail;
35
+struct AmMail;
36 36
 
37 37
 typedef std::map<std::string,std::string> EmailTmplDict;
38 38
 
... ...
@@ -731,13 +731,12 @@ void WebConferenceFactory::dialout(const AmArg& args, AmArg& ret) {
731 731
   AmArg* a = new AmArg();
732 732
   a->setBorrowedPointer(new UACAuthCred("", auth_user, auth_pwd));
733 733
 
734
-  AmSession* s = AmUAC::dialout(room.c_str(), APP_NAME,  to,  
735
-				"<" + from +  ">", from, "<" + to + ">", 
736
-				string(""), // callid
737
-				headers,    // headers
738
-				a);
739
-  if (s) {
740
-    string localtag = s->getLocalTag();
734
+  string localtag = AmUAC::dialout(room.c_str(), APP_NAME,  to,  
735
+				   "<" + from +  ">", from, "<" + to + ">", 
736
+				   string(""), // callid
737
+				   headers,    // headers
738
+				   a);
739
+  if (!localtag.empty()) {
741 740
     ret.push(0);
742 741
     ret.push("OK");
743 742
     ret.push(localtag.c_str());
... ...
@@ -157,6 +157,10 @@ stats_dir=/var/log/sems-webconference/
157 157
 #
158 158
 # minimum_timer=90
159 159
 
160
+# -  maximum Timer value we want to accept
161
+#
162
+#maximum_timer=900
163
+
160 164
 # session refresh (Session Timer, RFC4028) method
161 165
 #
162 166
 # INVITE                 - use re-INVITE
... ...
@@ -1,5 +1,6 @@
1 1
 /*
2 2
  * Copyright (C) 2007 iptego GmbH
3
+ * Copyright (C) 2010-2011 Stefan Sayer
3 4
  *
4 5
  * This file is part of SEMS, a free SIP media server.
5 6
  *
... ...
@@ -152,7 +153,7 @@ int XMLRPC2DI::load() {
152 153
     export_di = true;
153 154
   } 
154 155
   
155
-  DBG("XMLRPC Server: %snabling builtin method 'di'.\n", export_di?"E":"Not e");
156
+  INFO("XMLRPC Server: %snabling builtin method 'di'.\n", export_di?"E":"Not e");
156 157
 
157 158
 
158 159
   server = new XMLRPC2DIServer(XMLRPCPort, bind_ip, export_di, direct_export, s);
... ...
@@ -329,14 +330,30 @@ XMLRPC2DIServer::XMLRPC2DIServer(unsigned int port,
329 330
     s(s),
330 331
     // register method 'calls'
331 332
     calls_method(s),
332
-    // register method 'get_loglevel'
333
-    setloglevel_method(s),
334 333
     // register method 'set_loglevel'
335
-    getloglevel_method(s)
334
+    setloglevel_method(s),
335
+    // register method 'get_loglevel'
336
+    getloglevel_method(s),
337
+    // register method 'set_shutdownmode'
338
+    setshutdownmode_method(s),
339
+    // register method 'get_shutdownmode'
340
+    getshutdownmode_method(s),
341
+    getcallsavg_method(s),
342
+    getcallsmax_method(s),
343
+    getcpsavg_method(s),
344
+    getcpsmax_method(s)
345
+
346
+
336 347
 {	
337
-  DBG("XMLRPC Server: enabled builtin method 'calls'\n");
338
-  DBG("XMLRPC Server: enabled builtin method 'get_loglevel'\n");
339
-  DBG("XMLRPC Server: enabled builtin method 'set_loglevel'\n");
348
+  INFO("XMLRPC Server: enabled builtin method 'calls'\n");
349
+  INFO("XMLRPC Server: enabled builtin method 'get_loglevel'\n");
350
+  INFO("XMLRPC Server: enabled builtin method 'set_loglevel'\n");
351
+  INFO("XMLRPC Server: enabled builtin method 'get_shutdownmode'\n");
352
+  INFO("XMLRPC Server: enabled builtin method 'set_shutdownmode'\n");
353
+  INFO("XMLRPC Server: enabled builtin method 'get_callsavg'\n");
354
+  INFO("XMLRPC Server: enabled builtin method 'get_callsmax'\n");
355
+  INFO("XMLRPC Server: enabled builtin method 'get_cpsavg'\n");
356
+  INFO("XMLRPC Server: enabled builtin method 'get_cpsmax'\n");
340 357
 
341 358
   // export all methods via 'di' function? 
342 359
   if (di_export) {
... ...
@@ -350,9 +367,9 @@ XMLRPC2DIServer::XMLRPC2DIServer(unsigned int port,
350 367
     registerMethods(*it);
351 368
   }
352 369
 
353
-  DBG("Initialized XMLRPC2DIServer with: \n");
354
-  DBG("    IP = %s             port = %u\n", 
355
-      bind_ip.empty()?"ANY":bind_ip.c_str(), port);
370
+  INFO("Initialized XMLRPC2DIServer with: \n");
371
+  INFO("    IP = %s             port = %u\n", 
372
+       bind_ip.empty()?"ANY":bind_ip.c_str(), port);
356 373
 }
357 374
 
358 375
 /** register all methods on xmlrpc server listed by the iface 
... ...
@@ -389,14 +406,14 @@ void XMLRPC2DIServer::registerMethods(const std::string& iface) {
389 406
       }
390 407
       
391 408
       if (!has_method) {
392
-	DBG("XMLRPC Server: adding method '%s'\n",
393
-	    method.c_str());
409
+	INFO("XMLRPC Server: enabling method '%s'\n",
410
+	     method.c_str());
394 411
 	DIMethodProxy* mp = new DIMethodProxy(method, method, di_f);
395 412
 	s->addMethod(mp);
396 413
       }
397 414
       
398
-      DBG("XMLRPC Server: adding method '%s.%s'\n",
399
-	  iface.c_str(), method.c_str());
415
+      INFO("XMLRPC Server: enabling method '%s.%s'\n",
416
+	   iface.c_str(), method.c_str());
400 417
       DIMethodProxy* mp = new DIMethodProxy(iface + "." + method, 
401 418
 					    method, di_f);
402 419
       s->addMethod(mp);
... ...
@@ -441,6 +458,31 @@ void XMLRPC2DIServerSetLoglevelMethod::execute(XmlRpcValue& params, XmlRpcValue&
441 458
   result = "200 OK";
442 459
 }
443 460
 
461
+
462
+void XMLRPC2DIServerGetShutdownmodeMethod::execute(XmlRpcValue& params, XmlRpcValue& result) {
463
+  DBG("XMLRPC2DI: get_shutdownmode returns %s\n", AmConfig::ShutdownMode?"true":"false");
464
+  result = (bool)AmConfig::ShutdownMode;
465
+}
466
+
467
+void XMLRPC2DIServerSetShutdownmodeMethod::execute(XmlRpcValue& params, XmlRpcValue& result) {
468
+  AmConfig::ShutdownMode = params[0];
469
+  DBG("XMLRPC2DI: set shutdownmode to %s.\n", AmConfig::ShutdownMode?"true":"false");
470
+  result = "200 OK";
471
+}
472
+
473
+#define XMLMETH_EXEC(_meth, _sess_func, _descr)				\
474
+  void _meth::execute(XmlRpcValue& params, XmlRpcValue& result) {	\
475
+  unsigned int res = AmSession::_sess_func();				\
476
+  result = (int)res;							\
477
+  DBG("XMLRPC2DI: " _descr "(): %u\n", res);				\
478
+}
479
+
480
+XMLMETH_EXEC(XMLRPC2DIServerGetCallsavgMethod, getAvgSessionNum, "get_callsavg");
481
+XMLMETH_EXEC(XMLRPC2DIServerGetCallsmaxMethod, getMaxSessionNum, "get_callsmax");
482
+XMLMETH_EXEC(XMLRPC2DIServerGetCpsavgMethod,   getAvgCPS, "get_cpsavg");
483
+XMLMETH_EXEC(XMLRPC2DIServerGetCpsmaxMethod,   getMaxCPS, "get_cpsmax");
484
+#undef XMLMETH_EXEC
485
+
444 486
 void XMLRPC2DIServerDIMethod::execute(XmlRpcValue& params, XmlRpcValue& result) {
445 487
   try {
446 488
     if (params.size() < 2) {
... ...
@@ -57,6 +57,15 @@ DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerCallsMethod,       "calls");
57 57
 DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerSetLoglevelMethod, "set_loglevel");
58 58
 DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetLoglevelMethod, "get_loglevel");
59 59
 
60
+DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerSetShutdownmodeMethod, "set_shutdownmode");
61
+DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetShutdownmodeMethod, "get_shutdownmode");
62
+
63
+DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetCallsavgMethod, "get_callsavg");
64
+DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetCallsmaxMethod, "get_callsmax");
65
+DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetCpsavgMethod,   "get_cpsavg");
66
+DEF_XMLRPCSERVERMETHOD(XMLRPC2DIServerGetCpsmaxMethod,   "get_cpsmax");
67
+
68
+
60 69
 class XMLRPC2DIServerDIMethod 
61 70
 :  public XmlRpcServerMethod { 
62 71
   
... ...
@@ -90,6 +99,14 @@ class XMLRPC2DIServer : public AmThread {
90 99
   XMLRPC2DIServerCallsMethod       calls_method;
91 100
   XMLRPC2DIServerSetLoglevelMethod setloglevel_method;
92 101
   XMLRPC2DIServerGetLoglevelMethod getloglevel_method;
102
+  XMLRPC2DIServerSetShutdownmodeMethod setshutdownmode_method;
103
+  XMLRPC2DIServerGetShutdownmodeMethod getshutdownmode_method;
104
+
105
+  XMLRPC2DIServerGetCallsavgMethod  getcallsavg_method;
106
+  XMLRPC2DIServerGetCallsmaxMethod  getcallsmax_method;
107
+  XMLRPC2DIServerGetCpsavgMethod    getcpsavg_method;
108
+  XMLRPC2DIServerGetCpsmaxMethod    getcpsmax_method;
109
+
93 110
   XMLRPC2DIServerDIMethod*         di_method;
94 111
   void registerMethods(const std::string& iface);
95 112
 
... ...
@@ -383,7 +383,7 @@ XmlRpcClient::generateHeader(std::string const& body)
383 383
 
384 384
   header += "Content-Type: text/xml\r\nContent-length: ";
385 385
 
386
-  sprintf(buff,"%d\r\n\r\n", body.size());
386
+  sprintf(buff,"%zd\r\n\r\n", body.size());
387 387
 
388 388
   return header + buff;
389 389
 }
... ...
@@ -468,7 +468,7 @@ XmlRpcServer::generateHeader(std::string const& body)
468 468
     "Content-length: ";
469 469
 
470 470
   char buffLen[40];
471
-  sprintf(buffLen,"%d\r\n\r\n", body.size());
471
+  sprintf(buffLen,"%zd\r\n\r\n", body.size());
472 472
 
473 473
   return header + buffLen;
474 474
 }
... ...
@@ -7,13 +7,21 @@ INCLUDE_DIRECTORIES (../..)
7 7
 # issue then this name is equals to external library, our module links to.
8 8
 # E.g. the issue, then speex module should be linked to -lspeex
9 9
 
10
-ADD_LIBRARY(sems_dsm_${sems_dsm_module_name} SHARED ${${sems_dsm_module_name}_SRCS})
10
+ADD_LIBRARY(sems_dsm_${sems_dsm_module_name} MODULE ${${sems_dsm_module_name}_SRCS})
11
+
12
+IF(APPLE)
13
+	SET(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS
14
+		"${CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS} -flat_namespace -undefined suppress")
15
+	SET(CMAKE_SHARED_MODULE_CREATE_C_FLAGS
16
+		"${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -flat_namespace -undefined suppress")
17
+ENDIF(APPLE)
11 18
 
12 19
 # all modules should be linked against ${CMAKE_DL_LIBS} at least
13 20
 # and with additional ${sems_dsm_module_libs} if they exists
14 21
 TARGET_LINK_LIBRARIES(sems_dsm_${sems_dsm_module_name} ${CMAKE_DL_LIBS} ${sems_dsm_module_libs})
15 22
 
16 23
 SET_TARGET_PROPERTIES(sems_dsm_${sems_dsm_module_name} PROPERTIES OUTPUT_NAME ${sems_dsm_module_name})
24
+SET_TARGET_PROPERTIES(sems_dsm_${sems_dsm_module_name} PROPERTIES PREFIX "")
17 25
 
18 26
 INSTALL(
19 27
 	TARGETS sems_dsm_${sems_dsm_module_name}
... ...
@@ -8,7 +8,14 @@ INCLUDE(${CMAKE_SOURCE_DIR}/cmake/doc.rules.txt)
8 8
 INCLUDE(${CMAKE_SOURCE_DIR}/cmake/config.rules.txt)
9 9
 INCLUDE(${CMAKE_SOURCE_DIR}/cmake/audio.rules.txt)
10 10
 
11
-ADD_LIBRARY(sems_${sems_module_name} SHARED ${${sems_module_name}_SRCS})
11
+ADD_LIBRARY(sems_${sems_module_name} MODULE ${${sems_module_name}_SRCS})
12
+
13
+IF(APPLE)
14
+	SET(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS
15
+		"${CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS} -flat_namespace -undefined suppress")
16
+	SET(CMAKE_SHARED_MODULE_CREATE_C_FLAGS