1 /*
2  * Copyright (C) 2010-2011 Stefan Sayer
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS 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  * For a license to use the SEMS software under conditions
12  * other than those described here, or to purchase support for this
13  * software, please contact iptel.org by e-mail at the following addresses:
14  *    info@iptel.org
15  *
16  * SEMS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25 
26 #ifndef _SBCCallProfile_h
27 #define _SBCCallProfile_h
28 
29 #include "AmConfigReader.h"
30 #include "HeaderFilter.h"
31 #include "ampi/UACAuthAPI.h"
32 #include "ParamReplacer.h"
33 #include "atomic_types.h"
34 #include "sip/msg_logger.h"
35 
36 #include <set>
37 #include <string>
38 #include <map>
39 #include <list>
40 
41 using std::string;
42 using std::map;
43 using std::set;
44 using std::pair;
45 
46 typedef map<string, AmArg>   SBCVarMapT;
47 typedef SBCVarMapT::iterator SBCVarMapIteratorT;
48 typedef SBCVarMapT::const_iterator SBCVarMapConstIteratorT;
49 
50 struct CCInterface {
51   string cc_name;
52   string cc_module;
53   map<string, string> cc_values;
54 
CCInterfaceCCInterface55   CCInterface(string cc_name)
56   : cc_name(cc_name) { }
CCInterfaceCCInterface57   CCInterface() { }
58 };
59 
60 typedef std::list<CCInterface> CCInterfaceListT;
61 typedef CCInterfaceListT::iterator CCInterfaceListIteratorT;
62 typedef CCInterfaceListT::const_iterator CCInterfaceListConstIteratorT;
63 
64 template <class T>
65 class ref_counted_ptr
66 {
67   private:
68     T *ptr;
69 
70   public:
reset(T * p)71     void reset(T *p) { if (ptr) dec_ref(ptr); ptr = p; if (ptr) inc_ref(ptr); }
get()72     T *get() const { return ptr; }
73 
ref_counted_ptr()74     ref_counted_ptr(): ptr(0) { }
~ref_counted_ptr()75     ~ref_counted_ptr() { if (ptr) dec_ref(ptr); }
76 
ref_counted_ptr(const ref_counted_ptr & other)77     ref_counted_ptr(const ref_counted_ptr &other): ptr(other.ptr) { if (ptr) inc_ref(ptr); }
78     ref_counted_ptr &operator=(const ref_counted_ptr &other) { reset(other.ptr); return *this; }
79 
80 };
81 
82 class PayloadDesc {
83   protected:
84     std::string name;
85     unsigned clock_rate; // 0 means "doesn't matter"
86 
87   public:
88     bool match(const SdpPayload &p) const;
89     std::string print() const;
90     bool operator==(const PayloadDesc &other) const;
91 
92     /* FIXME: really want all of this?
93      * reads from format: name/clock_rate, nothing need to be set
94      * for example:
95      *	  PCMU
96      *	  bla/48000
97      *	  /48000
98      * */
99     bool read(const std::string &s);
100 };
101 
102 typedef pair<unsigned int, std::string> ReplyCodeReasonPair;
103 typedef map<unsigned int, ReplyCodeReasonPair> ReplyTranslationMap;
104 
105 struct SBCCallProfile
106   : public AmObject {
107   string md5hash;
108   string profile_file;
109 
110   string ruri;       /* updated if set */
111   string ruri_host;  /* updated if set */
112   string from;       /* updated if set */
113   string to;         /* updated if set */
114 
115   struct Contact {
116     string displayname;
117     string user;
118     string host;
119     string port;
120 
121     bool   hiding;
122     string hiding_prefix;
123     string hiding_vars;
124   };
125 
126   Contact contact;
127 
128   class BLegContact
129     : public AmUriParser
130   {
131     public:
132       bool readConfig(AmConfigReader &cfg);
133       bool evaluate(ParamReplacerCtx& ctx, const AmSipRequest& req);
134       void infoPrint() const;
135   } bleg_contact;
136 
137   string callid;
138 
139   string dlg_contact_params;
140 
141   bool transparent_dlg_id;
142   bool dlg_nat_handling;
143   bool keep_vias;
144   bool bleg_keep_vias;
145 
146   string outbound_proxy;
147   bool force_outbound_proxy;
148 
149   string aleg_outbound_proxy;
150   bool aleg_force_outbound_proxy;
151 
152   string next_hop;
153   bool next_hop_1st_req;
154   bool patch_ruri_next_hop;
155   bool next_hop_fixed;
156 
157   string aleg_next_hop;
158 
159   bool allow_subless_notify;
160 
161   vector<FilterEntry> headerfilter;
162   vector<FilterEntry> messagefilter;
163 
164   bool anonymize_sdp;
165   vector<FilterEntry> sdpfilter;
166   vector<FilterEntry> aleg_sdpfilter;
167   bool have_aleg_sdpfilter;
168   vector<FilterEntry> sdpalinesfilter;
169   vector<FilterEntry> mediafilter;
170 
171   string sst_enabled;
172   bool sst_enabled_value;
173   string sst_aleg_enabled;
174   AmConfigReader sst_a_cfg;    // SST config (A leg)
175   AmConfigReader sst_b_cfg;    // SST config (B leg)
176 
177   string fix_replaces_inv;
178   string fix_replaces_ref;
179 
180   bool auth_enabled;
181   UACAuthCred auth_credentials;
182 
183   bool auth_aleg_enabled;
184   UACAuthCred auth_aleg_credentials;
185   bool uas_auth_bleg_enabled;
186   UACAuthCred uas_auth_bleg_credentials;
187 
188   CCInterfaceListT cc_interfaces;
189 
190   SBCVarMapT cc_vars;
191 
192   ReplyTranslationMap reply_translations;
193 
194   string append_headers;
195   string append_headers_req;
196   string aleg_append_headers_req;
197 
198   string refuse_with;
199 
200   string rtprelay_enabled;
201   bool rtprelay_enabled_value;
202   string force_symmetric_rtp;
203   string aleg_force_symmetric_rtp;
204   bool force_symmetric_rtp_value;
205   bool aleg_force_symmetric_rtp_value;
206 
207   bool msgflags_symmetric_rtp;
208   bool rtprelay_transparent_seqno;
209   bool rtprelay_transparent_ssrc;
210   bool rtprelay_dtmf_filtering;
211   bool rtprelay_dtmf_detection;
212 
213   string rtprelay_interface;
214   int rtprelay_interface_value;
215   string aleg_rtprelay_interface;
216   int aleg_rtprelay_interface_value;
217 
218   int rtprelay_bw_limit_rate;
219   int rtprelay_bw_limit_peak;
220 
221   list<atomic_int*> aleg_rtp_counters;
222   list<atomic_int*> bleg_rtp_counters;
223 
224   string a_remote_rtp_mux_ip;
225   unsigned short a_remote_rtp_mux_port;
226   string b_remote_rtp_mux_ip;
227   unsigned short b_remote_rtp_mux_port;
228 
229   string outbound_interface;
230   int outbound_interface_value;
231 
232   string aleg_outbound_interface;
233   int aleg_outbound_interface_value;
234 
235   struct TranscoderSettings {
236     // non-replaced parameters
237     string callee_codec_capabilities_str, audio_codecs_str,
238       transcoder_mode_str, lowfi_codecs_str, dtmf_mode_str,
239       audio_codecs_norelay_str, audio_codecs_norelay_aleg_str;
240 
241     std::vector<PayloadDesc> callee_codec_capabilities;
242     std::vector<SdpPayload> audio_codecs;
243     std::vector<SdpPayload> audio_codecs_norelay;
244     std::vector<SdpPayload> audio_codecs_norelay_aleg;
245     std::vector<SdpPayload> lowfi_codecs;
246     enum { Always, OnMissingCompatible, Never } transcoder_mode;
247     enum { DTMFAlways, DTMFLowFiCodecs, DTMFNever } dtmf_mode;
248     bool readTranscoderMode(const std::string &src);
249     bool readDTMFMode(const std::string &src);
250 
251     bool enabled;
252 
253     bool evaluate(ParamReplacerCtx& ctx, const AmSipRequest& req);
254 
255     bool readConfig(AmConfigReader &cfg);
256     void infoPrint() const;
257     bool operator==(const TranscoderSettings& rhs) const;
258     string print() const;
259 
isActiveSBCCallProfile::TranscoderSettings260     bool isActive() { return enabled; }
TranscoderSettingsSBCCallProfile::TranscoderSettings261     TranscoderSettings(): transcoder_mode(Never), enabled(false) { }
262   } transcoder;
263 
264   struct CodecPreferences {
265     // non-replaced parameters
266     string aleg_prefer_existing_payloads_str, aleg_payload_order_str;
267     string bleg_prefer_existing_payloads_str, bleg_payload_order_str;
268 
269     /** when reordering payloads in relayed SDP from B leg to A leg prefer already
270      * present payloads to the added ones by transcoder; i.e. transcoder codecs
271      * are not ordered but added after ordering is done */
272     bool aleg_prefer_existing_payloads;
273     std::vector<PayloadDesc> aleg_payload_order;
274 
275     /** when reordering payloads in relayed SDP from A leg to B leg prefer already
276      * present payloads to the added ones by transcoder; i.e. transcoder codecs
277      * are not ordered but added after ordering is done */
278     bool bleg_prefer_existing_payloads;
279     std::vector<PayloadDesc> bleg_payload_order;
280 
281     bool readConfig(AmConfigReader &cfg);
282     void infoPrint() const;
283     bool operator==(const CodecPreferences& rhs) const;
284     string print() const;
285 
286     void orderSDP(AmSdp& sdp, bool a_leg); // do the SDP changes
287     bool shouldOrderPayloads(bool a_leg); // returns if call to orderSDP is needed
288 
289     // return true if ordering should be done before adding transcoder codecs
preferExistingCodecsSBCCallProfile::CodecPreferences290     bool preferExistingCodecs(bool a_leg) {
291       return a_leg ? bleg_prefer_existing_payloads : aleg_prefer_existing_payloads;
292     }
293 
294     bool evaluate(ParamReplacerCtx& ctx, const AmSipRequest& req);
295 
296     // default settings
CodecPreferencesSBCCallProfile::CodecPreferences297     CodecPreferences(): aleg_prefer_existing_payloads(false) ,bleg_prefer_existing_payloads(false) { }
298   } codec_prefs;
299 
300   bool contact_hiding;
301   string contact_hiding_prefix;
302   string contact_hiding_vars;
303 
304   bool reg_caching;
305   unsigned int min_reg_expires;
306   unsigned int max_ua_expires;
307 
308   // todo: RTP transcoding mode
309 
310   // hold settings
311   class HoldSettings {
312     public:
313         enum Activity { sendrecv, sendonly, recvonly, inactive };
314 
315     private:
316       struct HoldParams {
317         // non-replaced params
318         string mark_zero_connection_str, activity_str, alter_b2b_str;
319 
320         bool mark_zero_connection;
321         Activity activity;
322         bool alter_b2b; // transform B2B hold requests (not locally generated ones)
323 
324         bool setActivity(const string &s);
HoldParamsSBCCallProfile::HoldParams325         HoldParams(): mark_zero_connection(false), activity(sendonly), alter_b2b(false) { }
326       } aleg, bleg;
327 
328     public:
mark_zero_connectionSBCCallProfile329       bool mark_zero_connection(bool a_leg) { return a_leg ? aleg.mark_zero_connection : bleg.mark_zero_connection; }
activitySBCCallProfile330       Activity activity(bool a_leg) { return a_leg ? aleg.activity : bleg.activity; }
activity_strSBCCallProfile331       const string &activity_str(bool a_leg) { return a_leg ? aleg.activity_str : bleg.activity_str; }
alter_b2bSBCCallProfile332       bool alter_b2b(bool a_leg) { return a_leg ? aleg.alter_b2b : bleg.alter_b2b; }
333 
334       void readConfig(AmConfigReader &cfg);
335       bool evaluate(ParamReplacerCtx& ctx, const AmSipRequest& req);
336   } hold_settings;
337 
338   // maximum retry time for repeating reINVITE after 491 response (in
339   // milliseconds), according to RFC 3261 should be 2000 ms
340   int max_491_retry_time;
341 
342  private:
343   // message logging feature
344   string msg_logger_path;
345   ref_counted_ptr<msg_logger> logger;
346 
347   void create_logger(const AmSipRequest& req);
348 
349  public:
350   bool log_rtp;
351   bool log_sip;
has_loggerSBCCallProfile352   bool has_logger() { return logger.get() != NULL; }
353   msg_logger* get_logger(const AmSipRequest& req);
set_logger_pathSBCCallProfile354   void set_logger_path(const std::string path) { msg_logger_path = path; }
get_logger_pathSBCCallProfile355   const string &get_logger_path() { return msg_logger_path; }
356 
SBCCallProfileSBCCallProfile357   SBCCallProfile()
358   : transparent_dlg_id(false),
359     dlg_nat_handling(false),
360     keep_vias(false),
361     bleg_keep_vias(false),
362     next_hop_1st_req(false), patch_ruri_next_hop(false),
363     next_hop_fixed(false),
364     allow_subless_notify(false),
365     have_aleg_sdpfilter(false),
366     sst_enabled_value(false),
367     auth_enabled(false),
368     rtprelay_enabled_value(false),
369     force_symmetric_rtp_value(false),
370     aleg_force_symmetric_rtp_value(false),
371     rtprelay_transparent_seqno(true),
372     rtprelay_transparent_ssrc(true),
373     rtprelay_interface_value(-1),
374     aleg_rtprelay_interface_value(-1),
375     rtprelay_bw_limit_rate(-1),
376     rtprelay_bw_limit_peak(-1),
377     outbound_interface_value(-1),
378     contact_hiding(false),
379     reg_caching(false),
380     max_491_retry_time(2000),
381     log_rtp(false),
382     log_sip(false)
383   { }
384 
~SBCCallProfileSBCCallProfile385   ~SBCCallProfile()
386   { }
387 
388   bool readFromConfiguration(const string& name, const string profile_file_name);
389 
390   bool operator==(const SBCCallProfile& rhs) const;
391   string print() const;
392 
393   int refuse(ParamReplacerCtx& ctx, const AmSipRequest& req) const;
394 
395   int apply_a_routing(ParamReplacerCtx& ctx,
396 		      const AmSipRequest& req,
397 		      AmBasicSipDialog& dlg) const;
398 
399   int apply_b_routing(ParamReplacerCtx& ctx,
400 		      const AmSipRequest& req,
401 		      AmBasicSipDialog& dlg) const;
402 
403   int apply_common_fields(ParamReplacerCtx& ctx,
404 			  AmSipRequest& req) const;
405 
406   bool evaluateOutboundInterface();
407 
408   bool evaluate(ParamReplacerCtx& ctx,
409 		const AmSipRequest& req);
410 
411   bool evaluateRTPRelayInterface();
412   bool evaluateRTPRelayAlegInterface();
413 
414   void eval_sst_config(ParamReplacerCtx& ctx,
415 		       const AmSipRequest& req,
416 		       AmConfigReader& sst_cfg);
417 
418   void replace_cc_values(ParamReplacerCtx& ctx,
419 			 const AmSipRequest& req,
420 			 AmArg* values);
421 
422   void eval_cc_list(ParamReplacerCtx& ctx, const AmSipRequest& req);
423 
424   void fix_append_hdrs(ParamReplacerCtx& ctx, const AmSipRequest& req);
425 
426   void fix_reg_contact(ParamReplacerCtx& ctx, const AmSipRequest& req,
427 		       AmUriParser& contact) const;
428 
429   /**
430    * Reg-cache lookup:
431    * - searches for alias in the reg-cache.
432    * - sets next-hop & outbound_interface on the given dialog
433    * @return retargeted R-URI
434    */
435   string retarget(const string& alias, AmBasicSipDialog& dlg) const;
436 
437   /**
438    * Reg-cache lookup:
439    * - searches for alias in the reg-cache.
440    * - sets next-hop & outbound_interface in this profile
441    * @return retargeted R-URI
442    */
443   string retarget(const string& alias);
444 };
445 
446 #endif // _SBCCallProfile_h
447