Browse code

symmetrical B2B legs: common class made from SBCDialog and SBCCalleeSession

Work in progress - just compilable now.

Václav Kubart authored on 25/07/2012 11:53:56
Showing 4 changed files
... ...
@@ -47,6 +47,7 @@ SBC - feature-wishlist
47 47
 #include "HeaderFilter.h"
48 48
 #include "ParamReplacer.h"
49 49
 #include "SDPFilter.h"
50
+#include "SBCCallLeg.h"
50 51
 #include <algorithm>
51 52
 
52 53
 using std::map;
... ...
@@ -60,348 +61,6 @@ RegexMapper SBCFactory::regex_mappings;
60 61
 EXPORT_MODULE_FACTORY(SBCFactory);
61 62
 DEFINE_MODULE_INSTANCE(SBCFactory, MOD_NAME);
62 63
 
63
-// helper functions
64
-
65
-/** count active and inactive media streams in given SDP */
66
-static void countStreams(const AmSdp &sdp, int &active, int &inactive)
67
-{
68
-  active = 0;
69
-  inactive = 0;
70
-  for (vector<SdpMedia>::const_iterator m = sdp.media.begin(); m != sdp.media.end(); ++m) {
71
-    if (m->port == 0) inactive++;
72
-    else active++;
73
-  }
74
-}
75
-
76
-static const SdpPayload *findPayload(const std::vector<SdpPayload>& payloads, const SdpPayload &payload)
77
-{
78
-  string pname = payload.encoding_name;
79
-  transform(pname.begin(), pname.end(), pname.begin(), ::tolower);
80
-
81
-  for (vector<SdpPayload>::const_iterator p = payloads.begin(); p != payloads.end(); ++p) {
82
-    string s = p->encoding_name;
83
-    transform(s.begin(), s.end(), s.begin(), ::tolower);
84
-    if (s != pname) continue;
85
-    if (p->clock_rate != payload.clock_rate) continue;
86
-    if ((p->encoding_param >= 0) && (payload.encoding_param >= 0) && 
87
-        (p->encoding_param != payload.encoding_param)) continue;
88
-    return &(*p);
89
-  }
90
-  return NULL;
91
-}
92
-
93
-static bool containsPayload(const std::vector<SdpPayload>& payloads, const SdpPayload &payload)
94
-{
95
-  return findPayload(payloads, payload) != NULL;
96
-}
97
-
98
-static void savePayloadIDs(AmSdp &sdp, MediaType mtype, 
99
-    std::vector<SdpPayload> &transcoder_codecs,
100
-    PayloadIdMapping &mapping)
101
-{
102
-  unsigned stream_idx = 0;
103
-  for (vector<SdpMedia>::iterator m = sdp.media.begin(); m != sdp.media.end(); ++m) {
104
-    if (m->type != mtype) continue;
105
-
106
-    unsigned idx = 0;
107
-    for (vector<SdpPayload>::iterator p = transcoder_codecs.begin(); 
108
-        p != transcoder_codecs.end(); ++p, ++idx) 
109
-    {
110
-      if (p->payload_type < 0) {
111
-        const SdpPayload *pp = findPayload(m->payloads, *p);
112
-        if (pp && (pp->payload_type >= 0)) 
113
-          mapping.map(stream_idx, idx, pp->payload_type);
114
-      }
115
-    }
116
-
117
-    stream_idx++; // count chosen media type only
118
-  }
119
-}
120
-
121
-static void appendTranscoderCodecs(AmSdp &sdp, MediaType mtype, std::vector<SdpPayload> &transcoder_codecs, 
122
-    PayloadIdMapping &transcoder_payload_mapping)
123
-{
124
-  // append codecs for transcoding, remember the added ones to be able to filter
125
-  // them out from relayed reply!
126
-
127
-  // important: normalized SDP should get here
128
-
129
-  DBG("going to append transcoder codecs into SDP\n");
130
-
131
-  unsigned stream_idx = 0;
132
-  vector<SdpPayload>::const_iterator p;
133
-  for (vector<SdpMedia>::iterator m = sdp.media.begin(); m != sdp.media.end(); ++m) {
134
-
135
-    // handle audio transcoder codecs
136
-    if (m->type == mtype) {
137
-      // transcoder codecs can be added only if there are common payloads with
138
-      // the remote (only those allowed for transcoder)
139
-      // if there are no such common payloads adding transcoder codecs can't help
140
-      // because we won't be able to transcode later on!
141
-      // (we have to check for each media stream independently)
142
-
143
-      // find first unused dynamic payload number & detect transcodable codecs
144
-      // in original SDP
145
-      int id = 96;
146
-      bool transcodable = false;
147
-      PayloadMask used_payloads;
148
-      for (p = m->payloads.begin(); p != m->payloads.end(); ++p) {
149
-        if (p->payload_type >= id) id = p->payload_type + 1;
150
-        if (containsPayload(transcoder_codecs, *p)) transcodable = true;
151
-        used_payloads.set(p->payload_type);
152
-      }
153
-
154
-      if (transcodable) {
155
-        // there are some transcodable codecs present in the SDP, we can safely
156
-        // add the other transcoder codecs to the SDP
157
-        unsigned idx = 0;
158
-        for (p = transcoder_codecs.begin(); p != transcoder_codecs.end(); ++p, ++idx) {
159
-          // add all payloads which are not already there
160
-          if (!containsPayload(m->payloads, *p)) {
161
-            m->payloads.push_back(*p);
162
-            int &pid = m->payloads.back().payload_type;
163
-            if (pid < 0) {
164
-              // try to use remembered ID
165
-              pid = transcoder_payload_mapping.get(stream_idx, idx);
166
-            }
167
-
168
-            if ((pid < 0) || used_payloads.get(pid)) {
169
-              // payload ID is not set or is already used in current SDP, we
170
-              // need to assign a new one
171
-              pid = id++;
172
-            }
173
-          }
174
-        }
175
-        if (id > 128) ERROR("assigned too high payload type number (%d), see RFC 3551\n", id);
176
-      }
177
-      else {
178
-        // no compatible codecs found
179
-        DBG("can not transcode stream %d - no compatible codecs with transcoder_codecs found\n", stream_idx + 1);
180
-      }
181
-    
182
-      stream_idx++; // count chosen media type only
183
-    }
184
-  }
185
-
186
-  // remembered payload IDs should be used just once, in SDP answer
187
-  // unfortunatelly the SDP answer might be present in 1xx and in 2xx as well so
188
-  // we can't clear it here
189
-  // on other hand it might be useful to use the same payload ID if offer/answer
190
-  // is repeated in the other direction next time
191
-}
192
-
193
-// do the filtering, returns true if SDP was changed
194
-static bool doFiltering(AmSdp &sdp, SBCCallProfile &call_profile, bool a_leg, PayloadIdMapping &transcoder_payload_mapping)
195
-{
196
-  bool changed = false;
197
-
198
-  bool prefer_existing_codecs = call_profile.codec_prefs.preferExistingCodecs(a_leg);
199
-
200
-  if (prefer_existing_codecs) {
201
-    // We have to order payloads before adding transcoder codecs to leave
202
-    // transcoding as the last chance (existing codecs are preferred thus
203
-    // relaying will be used if possible).
204
-    if (call_profile.codec_prefs.shouldOrderPayloads(a_leg)) {
205
-      normalizeSDP(sdp, call_profile.anonymize_sdp);
206
-      call_profile.codec_prefs.orderSDP(sdp, a_leg);
207
-      changed = true;
208
-    }
209
-  }
210
-
211
-  // Add transcoder codecs before filtering because otherwise SDP filter could
212
-  // inactivate some media lines which shouldn't be inactivated.
213
-
214
-  if (call_profile.transcoder.isActive()) {
215
-    if (!changed) // otherwise already normalized
216
-      normalizeSDP(sdp, call_profile.anonymize_sdp);
217
-    appendTranscoderCodecs(sdp, MT_AUDIO, call_profile.transcoder.audio_codecs, transcoder_payload_mapping);
218
-    changed = true;
219
-  }
220
-  
221
-  if (!prefer_existing_codecs) {
222
-    // existing codecs are not preferred - reorder AFTER adding transcoder
223
-    // codecs so it might happen that transcoding will be forced though relaying
224
-    // would be possible
225
-    if (call_profile.codec_prefs.shouldOrderPayloads(a_leg)) {
226
-      if (!changed) normalizeSDP(sdp, call_profile.anonymize_sdp);
227
-      call_profile.codec_prefs.orderSDP(sdp, a_leg);
228
-      changed = true;
229
-    }
230
-  }
231
-  
232
-  // It doesn't make sense to filter out codecs allowed for transcoding and thus
233
-  // if the filter filters them out it can be considered as configuration
234
-  // problem, right? 
235
-  // => So we wouldn't try to avoid filtering out transcoder codecs what would
236
-  // just complicate things.
237
-
238
-  if (call_profile.sdpfilter_enabled) {
239
-    if (!changed) // otherwise already normalized
240
-      normalizeSDP(sdp, call_profile.anonymize_sdp);
241
-    if (isActiveFilter(call_profile.sdpfilter)) {
242
-      filterSDP(sdp, call_profile.sdpfilter, call_profile.sdpfilter_list);
243
-    }
244
-    changed = true;
245
-  }
246
-  if (call_profile.sdpalinesfilter_enabled &&
247
-      isActiveFilter(call_profile.sdpalinesfilter)) {
248
-    // filter SDP "a=lines"
249
-    filterSDPalines(sdp, call_profile.sdpalinesfilter, call_profile.sdpalinesfilter_list);
250
-    changed = true;
251
-  }
252
-
253
-  return changed;
254
-}
255
-
256
-static int filterBody(AmMimeBody *body, AmSdp& sdp, SBCCallProfile &call_profile, bool a_leg, 
257
-    PayloadIdMapping &transcoder_payload_mapping) 
258
-{
259
-  int res = sdp.parse((const char *)body->getPayload());
260
-  if (0 != res) {
261
-    DBG("SDP parsing failed!\n");
262
-    return res;
263
-  }
264
-
265
-  if (doFiltering(sdp, call_profile, a_leg, transcoder_payload_mapping)) {
266
-    string n_body;
267
-    sdp.print(n_body);
268
-    body->setPayload((const unsigned char*)n_body.c_str(),
269
-			 n_body.length());
270
-  }
271
-  return 0;
272
-}
273
-
274
-static int filterBody(AmSipRequest &req, AmSdp &sdp, SBCCallProfile &call_profile, bool a_leg, 
275
-    PayloadIdMapping &transcoder_payload_mapping)
276
-{
277
-  AmMimeBody* body = req.body.hasContentType(SIP_APPLICATION_SDP);
278
-
279
-  DBG("filtering SDP for request '%s'\n",
280
-      req.method.c_str());
281
-  if (body && 
282
-      (req.method == SIP_METH_INVITE || 
283
-       req.method == SIP_METH_UPDATE ||
284
-       req.method == SIP_METH_ACK)) {
285
-
286
-    // todo: handle filtering errors
287
-    filterBody(body, sdp, call_profile, a_leg, transcoder_payload_mapping);
288
-
289
-    // temporary hack - will be migrated deeper inside
290
-    int active, inactive;
291
-    countStreams(sdp, active, inactive);
292
-    if ((inactive > 0) && (active == 0)) {
293
-      // no active streams remaining => reply 488 (FIXME: does it matter if we
294
-      // filtered them out or they were already inactive?)
295
-
296
-      DBG("all streams are marked as inactive, reply 488 "
297
-          SIP_REPLY_NOT_ACCEPTABLE_HERE"\n");
298
-      return -488;
299
-    }
300
-  }
301
-  return 0;
302
-}
303
-
304
-static void filterBody(AmSipReply &reply, AmSdp &sdp, SBCCallProfile &call_profile, bool a_leg, 
305
-    PayloadIdMapping &transcoder_payload_mapping)
306
-{
307
-  AmMimeBody* body = reply.body.hasContentType(SIP_APPLICATION_SDP);
308
-
309
-  DBG("filtering body of relayed reply %d\n", reply.code);
310
-  if (body &&
311
-      (reply.cseq_method == SIP_METH_INVITE || reply.cseq_method == SIP_METH_UPDATE)) {
312
-    filterBody(body, sdp, call_profile, a_leg, transcoder_payload_mapping);
313
-  }
314
-}
315
-
316
-///////////////////////////////////////////////////////////////////////////////////////////
317
-
318
-class SBCRelayController: public RelayController {
319
-  private:
320
-    SBCCallProfile::TranscoderSettings *transcoder_settings;
321
-    bool aleg;
322
-
323
-  public:
324
-    SBCRelayController(SBCCallProfile::TranscoderSettings *t, bool _aleg): transcoder_settings(t), aleg(_aleg) { }
325
-
326
-    virtual void computeRelayMask(const SdpMedia &m, bool &enable, PayloadMask &mask);
327
-};
328
-
329
-void SBCRelayController::computeRelayMask(const SdpMedia &m, bool &enable, PayloadMask &mask)
330
-{
331
-  DBG("entering SBCRelayController::computeRelayMask(%s)\n", aleg ? "A leg" : "B leg");
332
-
333
-  PayloadMask m1, m2;
334
-  bool use_m1 = false;
335
-
336
-  /* if "m" contains only "norelay" codecs, relay is enabled for them (main idea
337
-   * of these codecs is to limit network bandwidth and it makes not much sense
338
-   * to transcode between codecs 'which are better to avoid', right?)
339
-   *
340
-   * if "m" contains other codecs, relay is enabled as well
341
-   *
342
-   * => if m contains at least some codecs, relay is enabled */
343
-  enable = !m.payloads.empty();
344
-
345
-  vector<SdpPayload> &norelay_payloads =
346
-    aleg ? transcoder_settings->audio_codecs_norelay_aleg : transcoder_settings->audio_codecs_norelay;
347
-
348
-  vector<SdpPayload>::const_iterator p;
349
-  for (p = m.payloads.begin(); p != m.payloads.end(); ++p) {
350
-
351
-    // do not mark telephone-event payload for relay (and do not use it for
352
-    // transcoding as well)
353
-    if(strcasecmp("telephone-event",p->encoding_name.c_str()) == 0) continue;
354
-
355
-    // mark every codec for relay in m2
356
-    DBG("m2: marking payload %d for relay\n", p->payload_type);
357
-    m2.set(p->payload_type);
358
-
359
-    if (!containsPayload(norelay_payloads, *p)) {
360
-      // this payload can be relayed
361
-
362
-      DBG("m1: marking payload %d for relay\n", p->payload_type);
363
-      m1.set(p->payload_type);
364
-
365
-      if (!use_m1 && containsPayload(transcoder_settings->audio_codecs, *p)) {
366
-        // the remote SDP contains transcodable codec which can be relayed (i.e.
367
-        // the one with higher "priority" so we want to disable relaying of the
368
-        // payloads which should not be ralyed if possible)
369
-        use_m1 = true;
370
-      }
371
-    }
372
-  }
373
-
374
-  DBG("using %s\n", use_m1 ? "m1" : "m2");
375
-  if (use_m1) mask = m1;
376
-  else mask = m2;
377
-}
378
-
379
-///////////////////////////////////////////////////////////////////////////////////////////
380
-
381
-// map stream index and transcoder payload index (two dimensions) into one under
382
-// presumption that there will be less than 128 payloads for transcoding
383
-// (might be handy to remember mapping only for dynamic ones (96-127)
384
-#define MAP_INDEXES(stream_idx, payload_idx) ((stream_idx) * 128 + payload_idx)
385
-
386
-void PayloadIdMapping::map(int stream_index, int payload_index, int payload_id)
387
-{
388
-  mapping[MAP_INDEXES(stream_index, payload_index)] = payload_id;
389
-}
390
-
391
-int PayloadIdMapping::get(int stream_index, int payload_index)
392
-{
393
-  std::map<int, int>::iterator i = mapping.find(MAP_INDEXES(stream_index, payload_index));
394
-  if (i != mapping.end()) return i->second;
395
-  else return -1;
396
-}
397
-
398
-void PayloadIdMapping::reset()
399
-{
400
-  mapping.clear();
401
-}
402
-
403
-#undef MAP_INDEXES
404
-
405 64
 ///////////////////////////////////////////////////////////////////////////////////////////
406 65
 
407 66
 SBCFactory::SBCFactory(const string& _app_name)
... ...
@@ -638,7 +297,7 @@ AmSession* SBCFactory::onInvite(const AmSipRequest& req, const string& app_name,
638 297
     }
639 298
   }
640 299
 
641
-  SBCDialog* b2b_dlg = new SBCDialog(call_profile);
300
+  SBCCallLeg* b2b_dlg = new SBCCallLeg(call_profile);
642 301
 
643 302
   if (call_profile.auth_aleg_enabled) {
644 303
     // adding auth handler
... ...
@@ -942,1142 +601,7 @@ void SBCFactory::postControlCmd(const AmArg& args, AmArg& ret) {
942 601
   }
943 602
 }
944 603
 
945
-SBCDialog::SBCDialog(const SBCCallProfile& call_profile)
946
-  : m_state(BB_Init),
947
-    auth(NULL),
948
-    call_profile(call_profile),
949
-    cc_timer_id(SBC_TIMER_ID_CALL_TIMERS_START)
950
-{
951
-  set_sip_relay_only(false);
952
-  dlg.setRel100State(Am100rel::REL100_IGNORED);
953
-
954
-  // better here than in onInvite
955
-  // or do we really want to start with OA when handling initial INVITE?
956
-  dlg.setOAEnabled(false);
957
-
958
-  memset(&call_connect_ts, 0, sizeof(struct timeval));
959
-  memset(&call_end_ts, 0, sizeof(struct timeval));
960
-}
961
-
962
-
963
-SBCDialog::~SBCDialog()
964
-{
965
-  if (auth)
966
-    delete auth;
967
-}
968
-
969
-UACAuthCred* SBCDialog::getCredentials() {
970
-  return &call_profile.auth_aleg_credentials;
971
-}
972
-
973
-void SBCDialog::fixupCCInterface(const string& val, CCInterface& cc_if) {
974
-  DBG("instantiating CC interface from '%s'\n", val.c_str());
975
-  size_t spos, last = val.length() - 1;
976
-  if (last < 0) {
977
-      spos = string::npos;
978
-      cc_if.cc_module = "";
979
-  } else {
980
-      spos = val.find(";", 0);
981
-      cc_if.cc_module = val.substr(0, spos);
982
-  }
983
-  DBG("    module='%s'\n", cc_if.cc_module.c_str());
984
-  while (spos < last) {
985
-      size_t epos = val.find("=", spos + 1);
986
-      if (epos == string::npos) {
987
-	  cc_if.cc_values.insert(make_pair(val.substr(spos + 1), ""));
988
-	  DBG("    '%s'='%s'\n", val.substr(spos + 1).c_str(), "");
989
-	  return;
990
-      }
991
-      if (epos == last) {
992
-	  cc_if.cc_values.insert(make_pair(val.substr(spos + 1, epos - spos - 1), ""));
993
-	  DBG("    '%s'='%s'\n", val.substr(spos + 1, epos - spos - 1).c_str(), "");
994
-	  return;
995
-      }
996
-      // if value starts with " char, it continues until another " is found
997
-      if (val[epos + 1] == '"') {
998
-	  if (epos + 1 == last) {
999
-	      cc_if.cc_values.insert(make_pair(val.substr(spos + 1, epos - spos - 1), ""));
1000
-	      DBG("    '%s'='%s'\n", val.substr(spos + 1, epos - spos - 1).c_str(), "");
1001
-	      return;
1002
-	  }
1003
-	  size_t qpos = val.find('"', epos + 2);
1004
-	  if (qpos == string::npos) {
1005
-	      cc_if.cc_values.insert(make_pair(val.substr(spos + 1, epos - spos -1), val.substr(epos + 2)));
1006
-	      DBG("    '%s'='%s'\n", val.substr(spos + 1, epos - spos - 1).c_str(), val.substr(epos + 2).c_str());
1007
-	      return;
1008
-	  }
1009
-	  cc_if.cc_values.insert(make_pair(val.substr(spos + 1, epos - spos - 1), val.substr(epos + 2, qpos - epos - 2)));
1010
-	  DBG("    '%s'='%s'\n", val.substr(spos + 1, epos - spos - 1).c_str(), val.substr(epos + 2, qpos - epos - 2).c_str());
1011
-	  if (qpos < last) {
1012
-	      spos = val.find(";", qpos + 1);
1013
-	  } else {
1014
-	      return;
1015
-	  }
1016
-      } else {
1017
-	  size_t new_spos = val.find(";", epos + 1);
1018
-	  if (new_spos == string::npos) {
1019
-	      cc_if.cc_values.insert(make_pair(val.substr(spos + 1, epos - spos - 1), val.substr(epos + 1)));
1020
-	      DBG("    '%s'='%s'\n", val.substr(spos + 1, epos - spos - 1).c_str(), val.substr(epos + 1).c_str());
1021
-	      return;
1022
-	  }
1023
-	  cc_if.cc_values.insert(make_pair(val.substr(spos + 1, epos - spos - 1), val.substr(epos + 1, new_spos - epos - 1)));
1024
-	  DBG("    '%s'='%s'\n", val.substr(spos + 1, epos - spos - 1).c_str(), val.substr(epos + 1, new_spos - epos - 1).c_str());
1025
-	  spos = new_spos;
1026
-      }
1027
-  }
1028
-  return;
1029
-}
1030
-
1031
-void SBCDialog::onInvite(const AmSipRequest& req)
1032
-{
1033
-  AmUriParser ruri_parser, from_parser, to_parser;
1034
-
1035
-  DBG("processing initial INVITE %s\n", req.r_uri.c_str());
1036
-
1037
-  string app_param = getHeader(req.hdrs, PARAM_HDR, true);
1038
-
1039
-  // get start time for call control
1040
-  if (call_profile.cc_interfaces.size()) {
1041
-    gettimeofday(&call_start_ts, NULL);
1042
-  }
1043
-
1044
-  // process call control
1045
-  if (call_profile.cc_interfaces.size()) {
1046
-    unsigned int cc_dynif_count = 0;
1047
-
1048
-    // fix up replacements in cc list
1049
-    CCInterfaceListIteratorT cc_rit = call_profile.cc_interfaces.begin();
1050
-    while (cc_rit != call_profile.cc_interfaces.end()) {
1051
-      CCInterfaceListIteratorT curr_if = cc_rit;
1052
-      cc_rit++;
1053
-      //      CCInterfaceListIteratorT next_cc = cc_rit+1;
1054
-      if (curr_if->cc_name.find('$') != string::npos) {
1055
-	vector<string> dyn_ccinterfaces =
1056
-	  explode(replaceParameters(curr_if->cc_name, "cc_interfaces", REPLACE_VALS), ",");
1057
-	if (!dyn_ccinterfaces.size()) {
1058
-	  DBG("call_control '%s' did not produce any call control instances\n",
1059
-	      curr_if->cc_name.c_str());
1060
-	  call_profile.cc_interfaces.erase(curr_if);
1061
-	} else {
1062
-	  // fill first CC interface (replacement item)
1063
-	  vector<string>::iterator it=dyn_ccinterfaces.begin();
1064
-	  curr_if->cc_name = "cc_dyn_"+int2str(cc_dynif_count++);
1065
-	  fixupCCInterface(trim(*it, " \t"), *curr_if);
1066
-	  it++;
1067
-
1068
-	  // insert other CC interfaces (in order!)
1069
-	  while (it != dyn_ccinterfaces.end()) {
1070
-	    CCInterfaceListIteratorT new_cc =
1071
-	      call_profile.cc_interfaces.insert(cc_rit, CCInterface());
1072
-	    fixupCCInterface(trim(*it, " \t"), *new_cc);
1073
-	    new_cc->cc_name = "cc_dyn_"+int2str(cc_dynif_count++);
1074
-	    it++;
1075
-	  }
1076
-	}
1077
-      }
1078
-    }
1079
-
1080
-    // fix up module names
1081
-    for (CCInterfaceListIteratorT cc_it=call_profile.cc_interfaces.begin();
1082
-	 cc_it != call_profile.cc_interfaces.end(); cc_it++) {
1083
-      cc_it->cc_module =
1084
-	replaceParameters(cc_it->cc_module, "cc_module", REPLACE_VALS);
1085
-    }
1086
-
1087
-    if (!getCCInterfaces()) {
1088
-      throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
1089
-    }
1090
-
1091
-    // fix up variables
1092
-    for (CCInterfaceListIteratorT cc_it=call_profile.cc_interfaces.begin();
1093
-	 cc_it != call_profile.cc_interfaces.end(); cc_it++) {
1094
-      CCInterface& cc_if = *cc_it;
1095
-
1096
-      DBG("processing replacements for call control interface '%s'\n",
1097
-	  cc_if.cc_name.c_str());
1098
-
1099
-      for (map<string, string>::iterator it = cc_if.cc_values.begin();
1100
-	   it != cc_if.cc_values.end(); it++) {
1101
-	it->second =
1102
-	  replaceParameters(it->second, it->first.c_str(), REPLACE_VALS);
1103
-      }
1104
-    }
1105
-
1106
-    if (!CCStart(req)) {
1107
-      setStopped();
1108
-      return;
1109
-    }
1110
-  }
1111
-
1112
-  if(dlg.reply(req, 100, "Connecting") != 0) {
1113
-    throw AmSession::Exception(500,"Failed to reply 100");
1114
-  }
1115
-
1116
-  if (!call_profile.evaluate(REPLACE_VALS)) {
1117
-    ERROR("call profile evaluation failed\n");
1118
-    throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
1119
-  }
1120
-
1121
-  ruri = call_profile.ruri.empty() ? req.r_uri : call_profile.ruri;
1122
-  if(!call_profile.ruri_host.empty()){
1123
-    ruri_parser.uri = ruri;
1124
-    if(!ruri_parser.parse_uri()) {
1125
-      WARN("Error parsing R-URI '%s'\n", ruri.c_str());
1126
-    }
1127
-    else {
1128
-      ruri_parser.uri_port.clear();
1129
-      ruri_parser.uri_host = call_profile.ruri_host;
1130
-      ruri = ruri_parser.uri_str();
1131
-    }
1132
-  }
1133
-  from = call_profile.from.empty() ? req.from : call_profile.from;
1134
-  to = call_profile.to.empty() ? req.to : call_profile.to;
1135
-  callid = call_profile.callid;
1136
-
1137
-  if (call_profile.rtprelay_enabled || call_profile.transcoder.isActive()) {
1138
-    DBG("Enabling RTP relay mode for SBC call\n");
1139
-
1140
-    if (call_profile.force_symmetric_rtp_value) {
1141
-      DBG("forcing symmetric RTP (passive mode)\n");
1142
-      rtp_relay_force_symmetric_rtp = true;
1143
-    }
1144
-
1145
-    if (call_profile.aleg_rtprelay_interface_value >= 0) {
1146
-      setRtpRelayInterface(call_profile.aleg_rtprelay_interface_value);
1147
-      DBG("using RTP interface %i for A leg\n", rtp_interface);
1148
-    }
1149
-
1150
-    setRtpRelayTransparentSeqno(call_profile.rtprelay_transparent_seqno);
1151
-    setRtpRelayTransparentSSRC(call_profile.rtprelay_transparent_ssrc);
1152
-
1153
-    setRtpRelayMode(RTP_Relay);
1154
-
1155
-    if(call_profile.transcoder.isActive()) {
1156
-      switch(call_profile.transcoder.dtmf_mode) {
1157
-      case SBCCallProfile::TranscoderSettings::DTMFAlways:
1158
-	enable_dtmf_transcoding = true; break;
1159
-      case SBCCallProfile::TranscoderSettings::DTMFNever:
1160
-	enable_dtmf_transcoding = false; break;
1161
-      case SBCCallProfile::TranscoderSettings::DTMFLowFiCodecs:
1162
-	enable_dtmf_transcoding = false;
1163
-	lowfi_payloads = call_profile.transcoder.lowfi_codecs;
1164
-	break;
1165
-      };
1166
-    }
1167
-  }
1168
-
1169
-  m_state = BB_Dialing;
1170
-
1171
-  // prepare request to relay to the B leg(s)
1172
-
1173
-  AmSipRequest invite_req(req);
1174
-  est_invite_cseq = req.cseq;
1175
-
1176
-  removeHeader(invite_req.hdrs,PARAM_HDR);
1177
-  removeHeader(invite_req.hdrs,"P-App-Name");
1178
-
1179
-  if (call_profile.sst_enabled_value) {
1180
-    removeHeader(invite_req.hdrs,SIP_HDR_SESSION_EXPIRES);
1181
-    removeHeader(invite_req.hdrs,SIP_HDR_MIN_SE);
1182
-  }
1183
-
1184
-  inplaceHeaderFilter(invite_req.hdrs,
1185
-		      call_profile.headerfilter_list, call_profile.headerfilter);
1186
-
1187
-  if (call_profile.append_headers.size() > 2) {
1188
-    string append_headers = call_profile.append_headers;
1189
-    assertEndCRLF(append_headers);
1190
-    invite_req.hdrs+=append_headers;
1191
-  }
1192
-  
1193
-  AmSdp sdp;
1194
-  int res = filterBody(invite_req, sdp, call_profile, a_leg, transcoder_payload_mapping);
1195
-  if (res < 0) {
1196
-    // FIXME: quick hack, throw the exception from the filtering function for
1197
-    // requests
1198
-    throw AmSession::Exception(488, SIP_REPLY_NOT_ACCEPTABLE_HERE);
1199
-  }
1200
-
1201
-#undef REPLACE_VALS
1202
-
1203
-  DBG("SBC: connecting to '%s'\n",ruri.c_str());
1204
-  DBG("     From:  '%s'\n",from.c_str());
1205
-  DBG("     To:  '%s'\n",to.c_str());
1206
-
1207
-  // we evaluated the settings, now we can initialize internals (like RTP relay)
1208
-  // we have to use original request (not the altered one) because for example
1209
-  // codecs filtered out might be used in direction to caller
1210
-  CallLeg::onInvite(req); 
1211
-  
1212
-  connectCallee(to, ruri, from, invite_req); // connect to the B leg(s) using modified request
1213
-}
1214
-
1215
-void SBCDialog::connectCallee(const string& remote_party, const string& remote_uri,
1216
-    const string &from, const AmSipRequest &invite)
1217
-{
1218
-  // FIXME: no fork for now
1219
-
1220
-  SBCCalleeSession* callee_session = new SBCCalleeSession(this, call_profile);
1221
-  callee_session->setLocalParty(from, from);
1222
-  callee_session->setRemoteParty(remote_party, remote_uri);
1223
-
1224
-  DBG("Created B2BUA callee leg, From: %s\n", from.c_str());
1225
-
1226
-  // FIXME: inconsistent with other filtering stuff - here goes the INVITE
1227
-  // already filtered so need not to be catched (can not) in relayEvent because
1228
-  // it is sent other way
1229
-  addCallee(callee_session, invite);
1230
-  
1231
-  // we could start in SIP relay mode from the beginning if only one B leg, but
1232
-  // serial fork might mess it
1233
-  // set_sip_relay_only(true);
1234
-}
1235
-
1236
-bool SBCDialog::getCCInterfaces() {
1237
-  for (CCInterfaceListIteratorT cc_it=call_profile.cc_interfaces.begin();
1238
-       cc_it != call_profile.cc_interfaces.end(); cc_it++) {
1239
-    string& cc_module = cc_it->cc_module;
1240
-    if (cc_module.empty()) {
1241
-      ERROR("using call control but empty cc_module for '%s'!\n", cc_it->cc_name.c_str());
1242
-      return false;
1243
-    }
1244
-
1245
-    AmDynInvokeFactory* cc_fact = AmPlugIn::instance()->getFactory4Di(cc_module);
1246
-    if (NULL == cc_fact) {
1247
-      ERROR("cc_module '%s' not loaded\n", cc_module.c_str());
1248
-      return false;
1249
-    }
1250
-
1251
-    AmDynInvoke* cc_di = cc_fact->getInstance();
1252
-    if(NULL == cc_di) {
1253
-      ERROR("could not get a DI reference\n");
1254
-      return false;
1255
-    }
1256
-    cc_modules.push_back(cc_di);
1257
-  }
1258
-  return true;
1259
-}
1260
-
1261
-void SBCDialog::process(AmEvent* ev)
1262
-{
1263
-
1264
-  AmPluginEvent* plugin_event = dynamic_cast<AmPluginEvent*>(ev);
1265
-  if(plugin_event && plugin_event->name == "timer_timeout") {
1266
-    int timer_id = plugin_event->data.get(0).asInt();
1267
-    if (timer_id >= SBC_TIMER_ID_CALL_TIMERS_START &&
1268
-	timer_id <= SBC_TIMER_ID_CALL_TIMERS_END) {
1269
-      DBG("timer %d timeout, stopping call\n", timer_id);
1270
-      stopCall();
1271
-      ev->processed = true;
1272
-    }
1273
-  }
1274
-
1275
-  SBCCallTimerEvent* ct_event;
1276
-  if (ev->event_id == SBCCallTimerEvent_ID &&
1277
-      (ct_event = dynamic_cast<SBCCallTimerEvent*>(ev)) != NULL) {
1278
-    switch (m_state) {
1279
-    case BB_Connected: {
1280
-      switch (ct_event->timer_action) {
1281
-      case SBCCallTimerEvent::Remove:
1282
-	DBG("removing timer %d on call timer request\n", ct_event->timer_id);
1283
-	removeTimer(ct_event->timer_id); return;
1284
-      case SBCCallTimerEvent::Set:
1285
-	DBG("setting timer %d to %f on call timer request\n",
1286
-	    ct_event->timer_id, ct_event->timeout);
1287
-	setTimer(ct_event->timer_id, ct_event->timeout); return;
1288
-      case SBCCallTimerEvent::Reset:
1289
-	DBG("resetting timer %d to %f on call timer request\n",
1290
-	    ct_event->timer_id, ct_event->timeout);
1291
-	removeTimer(ct_event->timer_id);
1292
-	setTimer(ct_event->timer_id, ct_event->timeout);
1293
-	return;
1294
-      default: ERROR("unknown timer_action in sbc call timer event\n"); return;
1295
-      }
1296
-    }
1297
-
1298
-    case BB_Init:
1299
-    case BB_Dialing: {
1300
-      switch (ct_event->timer_action) {
1301
-      case SBCCallTimerEvent::Remove: clearCallTimer(ct_event->timer_id); return;
1302
-      case SBCCallTimerEvent::Set:
1303
-      case SBCCallTimerEvent::Reset:
1304
-	saveCallTimer(ct_event->timer_id, ct_event->timeout); return;
1305
-      default: ERROR("unknown timer_action in sbc call timer event\n"); return;
1306
-      }
1307
-    } break;
1308
-
1309
-    default: break;
1310
-    }
1311
-  }
1312
-
1313
-  SBCControlEvent* ctl_event;
1314
-  if (ev->event_id == SBCControlEvent_ID &&
1315
-      (ctl_event = dynamic_cast<SBCControlEvent*>(ev)) != NULL) {
1316
-    onControlCmd(ctl_event->cmd, ctl_event->params);
1317
-    return;
1318
-  }
1319
-
1320
-  CallLeg::process(ev);
1321
-}
1322
-
1323
-void SBCDialog::onControlCmd(string& cmd, AmArg& params) {
1324
-  if (cmd == "teardown") {
1325
-    DBG("teardown requested from control cmd\n");
1326
-    stopCall();
1327
-    return;
1328
-  }
1329
-  DBG("ignoring unknown control cmd : '%s'\n", cmd.c_str());
1330
-}
1331
-
1332
-int SBCDialog::relayEvent(AmEvent* ev)
1333
-{
1334
-    switch (ev->event_id) {
1335
-      case B2BSipRequest:
1336
-        {
1337
-          B2BSipRequestEvent* req_ev = dynamic_cast<B2BSipRequestEvent*>(ev);
1338
-
1339
-          if (isActiveFilter(call_profile.headerfilter)) {
1340
-            //B2BSipRequestEvent* req_ev = dynamic_cast<B2BSipRequestEvent*>(ev);
1341
-            // header filter
1342
-            assert(req_ev);
1343
-            inplaceHeaderFilter(req_ev->req.hdrs,
1344
-                call_profile.headerfilter_list, call_profile.headerfilter);
1345
-          }
1346
-
1347
-          DBG("filtering body for request '%s' (c/t '%s')\n",
1348
-              req_ev->req.method.c_str(), req_ev->req.body.getCTStr().c_str());
1349
-          // todo: handle filtering errors
1350
-
1351
-          AmSdp sdp;
1352
-          int res = filterBody(req_ev->req, sdp, call_profile, a_leg, transcoder_payload_mapping);
1353
-          if (res < 0) return res;
1354
-        }
1355
-        break;
1356
-
1357
-      case B2BSipReply:
1358
-        {
1359
-          B2BSipReplyEvent* reply_ev = dynamic_cast<B2BSipReplyEvent*>(ev);
1360
-
1361
-          if (isActiveFilter(call_profile.headerfilter) ||
1362
-              call_profile.reply_translations.size()) {
1363
-            assert(reply_ev);
1364
-            // header filter
1365
-            if (isActiveFilter(call_profile.headerfilter)) {
1366
-              inplaceHeaderFilter(reply_ev->reply.hdrs,
1367
-                  call_profile.headerfilter_list,
1368
-                  call_profile.headerfilter);
1369
-            }
1370
-
1371
-            // reply translations
1372
-            map<unsigned int, pair<unsigned int, string> >::iterator it =
1373
-              call_profile.reply_translations.find(reply_ev->reply.code);
1374
-            if (it != call_profile.reply_translations.end()) {
1375
-              DBG("translating reply %u %s => %u %s\n",
1376
-                  reply_ev->reply.code, reply_ev->reply.reason.c_str(),
1377
-                  it->second.first, it->second.second.c_str());
1378
-              reply_ev->reply.code = it->second.first;
1379
-              reply_ev->reply.reason = it->second.second;
1380
-            }
1381
-          }
1382
-
1383
-          DBG("filtering body for reply '%s' (c/t '%s')\n",
1384
-              reply_ev->trans_method.c_str(), reply_ev->reply.body.getCTStr().c_str());
1385
-
1386
-          AmSdp sdp;
1387
-          filterBody(reply_ev->reply, sdp, call_profile, a_leg, transcoder_payload_mapping);
1388
-        }
1389
-
1390
-        break;
1391
-    }
1392
-
1393
-  return CallLeg::relayEvent(ev);
1394
-}
1395
-
1396
-void SBCDialog::onSipRequest(const AmSipRequest& req) {
1397
-  // AmB2BSession does not call AmSession::onSipRequest for 
1398
-  // forwarded requests - so lets call event handlers here
1399
-  // todo: this is a hack, replace this by calling proper session 
1400
-  // event handler in AmB2BSession
1401
-  bool fwd = sip_relay_only &&
1402
-    //(req.method != "BYE") &&
1403
-    (req.method != "CANCEL");
1404
-  if (fwd) {
1405
-      CALL_EVENT_H(onSipRequest,req);
1406
-  }
1407
-
1408
-  if (fwd && isActiveFilter(call_profile.messagefilter)) {
1409
-    bool is_filtered = (call_profile.messagefilter == Whitelist) ^ 
1410
-      (call_profile.messagefilter_list.find(req.method) != 
1411
-       call_profile.messagefilter_list.end());
1412
-    if (is_filtered) {
1413
-      DBG("replying 405 to filtered message '%s'\n", req.method.c_str());
1414
-      dlg.reply(req, 405, "Method Not Allowed", NULL, "", SIP_FLAGS_VERBATIM);
1415
-      return;
1416
-    }
1417
-  }
1418
-
1419
-  CallLeg::onSipRequest(req);
1420
-}
1421
-
1422
-void SBCDialog::onSipReply(const AmSipReply& reply, AmSipDialog::Status old_dlg_status)
1423
-{
1424
-  TransMap::iterator t = relayed_req.find(reply.cseq);
1425
-  bool fwd = t != relayed_req.end();
1426
-
1427
-  DBG("onSipReply: %i %s (fwd=%i)\n",reply.code,reply.reason.c_str(),fwd);
1428
-  DBG("onSipReply: content-type = %s\n",reply.body.getCTStr().c_str());
1429
-  if (fwd) {
1430
-      CALL_EVENT_H(onSipReply,reply, old_dlg_status);
1431
-  }
1432
-
1433
-  if (NULL == auth) {
1434
-    CallLeg::onSipReply(reply, old_dlg_status);
1435
-    return;
1436
-  }
1437
-
1438
-  // only for SIP authenticated
1439
-  unsigned int cseq_before = dlg.cseq;
1440
-  if (!auth->onSipReply(reply, old_dlg_status)) {
1441
-      CallLeg::onSipReply(reply, old_dlg_status);
1442
-  } else {
1443
-    if (cseq_before != dlg.cseq) {
1444
-      DBG("uac_auth consumed reply with cseq %d and resent with cseq %d; "
1445
-          "updating relayed_req map\n", reply.cseq, cseq_before);
1446
-      updateUACTransCSeq(reply.cseq, cseq_before);
1447
-    }
1448
-  }
1449
-}
1450
-
1451
-void SBCDialog::onSendRequest(AmSipRequest& req, int flags) {
1452
-  if (NULL != auth) {
1453
-    DBG("auth->onSendRequest cseq = %d\n", req.cseq);
1454
-    auth->onSendRequest(req, flags);
1455
-  }
1456
-
1457
-  CallLeg::onSendRequest(req, flags);
1458
-}
1459
-
1460
-void SBCDialog::onCallConnected(const AmSipReply& reply) {
1461
-  m_state = BB_Connected;
1462
-
1463
-  if (!startCallTimers())
1464
-    return;
1465
-
1466
-  if (call_profile.cc_interfaces.size()) {
1467
-    gettimeofday(&call_connect_ts, NULL);
1468
-  }
1469
-
1470
-  CCConnect(reply);
1471
-}
1472 604
 
1473
-void SBCDialog::onCallStopped() {
1474
-  if (call_profile.cc_interfaces.size()) {
1475
-    gettimeofday(&call_end_ts, NULL);
1476
-  }
1477
-
1478
-  if (m_state == BB_Connected) {
1479
-    stopCallTimers();
1480
-  }
1481
-
1482
-  m_state = BB_Teardown;
1483
-
1484
-  CCEnd();
1485
-}
1486
-
1487
-void SBCDialog::onOtherBye(const AmSipRequest& req)
1488
-{
1489
-  onCallStopped();
1490
-
1491
-  CallLeg::onOtherBye(req);
1492
-}
1493
-
1494
-void SBCDialog::onSessionTimeout() {
1495
-  onCallStopped();
1496
-
1497
-  CallLeg::onSessionTimeout();
1498
-}
1499
-
1500
-void SBCDialog::onNoAck(unsigned int cseq) {
1501
-  onCallStopped();
1502
-
1503
-  CallLeg::onNoAck(cseq);
1504
-}
1505
-
1506
-void SBCDialog::onRemoteDisappeared(const AmSipReply& reply)  {
1507
-  DBG("Remote unreachable - ending SBC call\n");
1508
-  onCallStopped();
1509
-
1510
-  CallLeg::onRemoteDisappeared(reply);
1511
-}
1512
-
1513
-void SBCDialog::onBye(const AmSipRequest& req)
1514
-{
1515
-  DBG("onBye()\n");
1516
-
1517
-  onCallStopped();
1518
-
1519
-  CallLeg::onBye(req);
1520
-}
1521
-
1522
-void SBCDialog::onCancel(const AmSipRequest& cancel)
1523
-{
1524
-  dlg.bye();
1525
-  stopCall();
1526
-}
1527
-
1528
-void SBCDialog::onDtmf(int event, int duration)
1529
-{
1530
-  if(media_session) {
1531
-    DBG("received DTMF on %c-leg (%i;%i)\n",
1532
-	a_leg ? 'A': 'B', event, duration);
1533
-    media_session->sendDtmf(!a_leg,event,duration);
1534
-  }
1535
-}
1536
-
1537
-void SBCDialog::onSystemEvent(AmSystemEvent* ev) {
1538
-  if (ev->sys_event == AmSystemEvent::ServerShutdown) {
1539
-    onCallStopped();
1540
-  }
1541
-
1542
-  CallLeg::onSystemEvent(ev);
1543
-}
1544
-
1545
-void SBCDialog::stopCall() {
1546
-  terminateOtherLeg();
1547
-  terminateLeg();
1548
-  onCallStopped();
1549
-}
1550
-
1551
-void SBCDialog::saveCallTimer(int timer, double timeout) {
1552
-  call_timers[timer] = timeout;
1553
-}
1554
-
1555
-void SBCDialog::clearCallTimer(int timer) {
1556
-  call_timers.erase(timer);
1557
-}
1558
-
1559
-void SBCDialog::clearCallTimers() {
1560
-  call_timers.clear();
1561
-}
1562
-
1563
-/** @return whether successful */
1564
-bool SBCDialog::startCallTimers() {
1565
-  for (map<int, double>::iterator it=
1566
-	 call_timers.begin(); it != call_timers.end(); it++) {
1567
-    DBG("SBC: starting call timer %i of %f seconds\n", it->first, it->second);
1568
-    setTimer(it->first, it->second);
1569
-  }
1570
-
1571
-  return true;
1572
-}
1573
-
1574
-void SBCDialog::stopCallTimers() {
1575
-  for (map<int, double>::iterator it=
1576
-	 call_timers.begin(); it != call_timers.end(); it++) {
1577
-    DBG("SBC: removing call timer %i\n", it->first);
1578
-    removeTimer(it->first);
1579
-  }
1580
-}
1581
-
1582
-bool SBCDialog::CCStart(const AmSipRequest& req) {
1583
-  vector<AmDynInvoke*>::iterator cc_mod=cc_modules.begin();
1584
-
1585
-  for (CCInterfaceListIteratorT cc_it=call_profile.cc_interfaces.begin();
1586
-       cc_it != call_profile.cc_interfaces.end(); cc_it++) {
1587
-    CCInterface& cc_if = *cc_it;
1588
-
1589
-    AmArg di_args,ret;
1590
-    di_args.push(cc_if.cc_name);
1591
-    di_args.push(getLocalTag());
1592
-    di_args.push((AmObject*)&call_profile);
1593
-    di_args.push(AmArg());
1594
-    di_args.back().push((int)call_start_ts.tv_sec);
1595
-    di_args.back().push((int)call_start_ts.tv_usec);
1596
-    for (int i=0;i<4;i++)
1597
-      di_args.back().push((int)0);
1598
-
1599
-    di_args.push(AmArg());
1600
-    AmArg& vals = di_args.back();
1601
-    vals.assertStruct();
1602
-    for (map<string, string>::iterator it = cc_if.cc_values.begin();
1603
-	 it != cc_if.cc_values.end(); it++) {
1604
-      vals[it->first] = it->second;
1605
-    }
1606
-
1607
-    di_args.push(cc_timer_id); // current timer ID
1608
-
1609
-    try {
1610
-      (*cc_mod)->invoke("start", di_args, ret);
1611
-    } catch (const AmArg::OutOfBoundsException& e) {
1612
-      ERROR("OutOfBoundsException executing call control interface start "
1613
-	    "module '%s' named '%s', parameters '%s'\n",
1614
-	    cc_if.cc_module.c_str(), cc_if.cc_name.c_str(),
1615
-	    AmArg::print(di_args).c_str());
1616
-      dlg.reply(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR);
1617
-
1618
-      // call 'end' of call control modules up to here
1619
-      call_end_ts.tv_sec = call_start_ts.tv_sec;
1620
-      call_end_ts.tv_usec = call_start_ts.tv_usec;
1621
-      CCEnd(cc_it);
1622
-
1623
-      return false;
1624
-    } catch (const AmArg::TypeMismatchException& e) {
1625
-      ERROR("TypeMismatchException executing call control interface start "
1626
-	    "module '%s' named '%s', parameters '%s'\n",
1627
-	    cc_if.cc_module.c_str(), cc_if.cc_name.c_str(),
1628
-	    AmArg::print(di_args).c_str());
1629
-      dlg.reply(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR);
1630
-
1631
-      // call 'end' of call control modules up to here
1632
-      call_end_ts.tv_sec = call_start_ts.tv_sec;
1633
-      call_end_ts.tv_usec = call_start_ts.tv_usec;
1634
-      CCEnd(cc_it);
1635
-
1636
-      return false;
1637
-    }
1638
-
1639
-    // evaluate ret
1640
-    if (isArgArray(ret)) {
1641
-      for (size_t i=0;i<ret.size();i++) {
1642
-	if (!isArgArray(ret[i]) || !ret[i].size())
1643
-	  continue;
1644
-	if (!isArgInt(ret[i][SBC_CC_ACTION])) {
1645
-	  ERROR("in call control module '%s' - action type not int\n",
1646
-		cc_if.cc_name.c_str());
1647
-	  continue;
1648
-	}
1649
-	switch (ret[i][SBC_CC_ACTION].asInt()) {
1650
-	case SBC_CC_DROP_ACTION: {
1651
-	  DBG("dropping call on call control action DROP from '%s'\n",
1652
-	      cc_if.cc_name.c_str());
1653
-	  dlg.setStatus(AmSipDialog::Disconnected);
1654
-
1655
-	  // call 'end' of call control modules up to here
1656
-	  call_end_ts.tv_sec = call_start_ts.tv_sec;
1657
-	  call_end_ts.tv_usec = call_start_ts.tv_usec;
1658
-	  CCEnd(cc_it);
1659
-
1660
-	  return false;
1661
-	}
1662
-
1663
-	case SBC_CC_REFUSE_ACTION: {
1664
-	  if (ret[i].size() < 3 ||
1665
-	      !isArgInt(ret[i][SBC_CC_REFUSE_CODE]) ||
1666
-	      !isArgCStr(ret[i][SBC_CC_REFUSE_REASON])) {
1667
-	    ERROR("in call control module '%s' - REFUSE action parameters missing/wrong: '%s'\n",
1668
-		  cc_if.cc_name.c_str(), AmArg::print(ret[i]).c_str());
1669
-	    continue;
1670
-	  }
1671
-	  string headers;
1672
-	  if (ret[i].size() > SBC_CC_REFUSE_HEADERS) {
1673
-	    for (size_t h=0;h<ret[i][SBC_CC_REFUSE_HEADERS].size();h++)
1674
-	      headers += string(ret[i][SBC_CC_REFUSE_HEADERS][h].asCStr()) + CRLF;
1675
-	  }
1676
-
1677
-	  DBG("replying with %d %s on call control action REFUSE from '%s' headers='%s'\n",
1678
-	      ret[i][SBC_CC_REFUSE_CODE].asInt(), ret[i][SBC_CC_REFUSE_REASON].asCStr(),
1679
-	      cc_if.cc_name.c_str(), headers.c_str());
1680
-
1681
-	  dlg.reply(req,
1682
-		    ret[i][SBC_CC_REFUSE_CODE].asInt(), ret[i][SBC_CC_REFUSE_REASON].asCStr(),
1683
-		    NULL, headers);
1684
-
1685
-	  // call 'end' of call control modules up to here
1686
-	  call_end_ts.tv_sec = call_start_ts.tv_sec;
1687
-	  call_end_ts.tv_usec = call_start_ts.tv_usec;
1688
-	  CCEnd(cc_it);
1689
-	  return false;
1690
-	}
1691
-
1692
-	case SBC_CC_SET_CALL_TIMER_ACTION: {
1693
-	  if (cc_timer_id > SBC_TIMER_ID_CALL_TIMERS_END) {
1694
-	    ERROR("too many call timers - ignoring timer\n");
1695
-	    continue;
1696
-	  }
1697
-
1698
-	  if (ret[i].size() < 2 ||
1699
-	      (!(isArgInt(ret[i][SBC_CC_TIMER_TIMEOUT]) ||
1700
-		 isArgDouble(ret[i][SBC_CC_TIMER_TIMEOUT])))) {
1701
-	    ERROR("in call control module '%s' - SET_CALL_TIMER action parameters missing: '%s'\n",
1702
-		  cc_if.cc_name.c_str(), AmArg::print(ret[i]).c_str());
1703
-	    continue;
1704
-	  }
1705
-
1706
-	  double timeout;
1707
-	  if (isArgInt(ret[i][SBC_CC_TIMER_TIMEOUT]))
1708
-	    timeout = ret[i][SBC_CC_TIMER_TIMEOUT].asInt();
1709
-	  else
1710
-	    timeout = ret[i][SBC_CC_TIMER_TIMEOUT].asDouble();
1711
-
1712
-	  DBG("saving call timer %i: timeout %f\n", cc_timer_id, timeout);
1713
-	  saveCallTimer(cc_timer_id, timeout);
1714
-	  cc_timer_id++;
1715
-	} break;
1716
-	default: {
1717
-	  ERROR("unknown call control action: '%s'\n", AmArg::print(ret[i]).c_str());
1718
-	  continue;
1719
-	}
1720
-
1721
-	}
1722
-
1723
-      }
1724
-    }
1725
-
1726
-    cc_mod++;
1727
-  }
1728
-  return true;
1729
-}
1730
-
1731
-void SBCDialog::CCConnect(const AmSipReply& reply) {
1732
-  vector<AmDynInvoke*>::iterator cc_mod=cc_modules.begin();
1733
-
1734
-  for (CCInterfaceListIteratorT cc_it=call_profile.cc_interfaces.begin();
1735
-       cc_it != call_profile.cc_interfaces.end(); cc_it++) {
1736
-    CCInterface& cc_if = *cc_it;
1737
-
1738
-    AmArg di_args,ret;
1739
-    di_args.push(cc_if.cc_name);                // cc name
1740
-    di_args.push(getLocalTag());                 // call ltag
1741
-    di_args.push((AmObject*)&call_profile);     // call profile
1742
-    di_args.push(AmArg());                       // timestamps
1743
-    di_args.back().push((int)call_start_ts.tv_sec);
1744
-    di_args.back().push((int)call_start_ts.tv_usec);
1745
-    di_args.back().push((int)call_connect_ts.tv_sec);
1746
-    di_args.back().push((int)call_connect_ts.tv_usec);
1747
-    for (int i=0;i<2;i++)
1748
-      di_args.back().push((int)0);
1749
-    di_args.push(other_id);                      // other leg ltag
1750
-
1751
-
1752
-    try {
1753
-      (*cc_mod)->invoke("connect", di_args, ret);
1754
-    } catch (const AmArg::OutOfBoundsException& e) {
1755
-      ERROR("OutOfBoundsException executing call control interface connect "
1756
-	    "module '%s' named '%s', parameters '%s'\n",
1757
-	    cc_if.cc_module.c_str(), cc_if.cc_name.c_str(),
1758
-	    AmArg::print(di_args).c_str());
1759
-      stopCall();
1760
-      return;
1761
-    } catch (const AmArg::TypeMismatchException& e) {
1762
-      ERROR("TypeMismatchException executing call control interface connect "
1763
-	    "module '%s' named '%s', parameters '%s'\n",
1764
-	    cc_if.cc_module.c_str(), cc_if.cc_name.c_str(),
1765
-	    AmArg::print(di_args).c_str());
1766
-      stopCall();
1767
-      return;
1768
-    }
1769
-
1770
-    cc_mod++;
1771
-  }
1772
-}
1773
-
1774
-void SBCDialog::CCEnd() {
1775
-  CCEnd(call_profile.cc_interfaces.end());
1776
-}
1777
-
1778
-void SBCDialog::CCEnd(const CCInterfaceListIteratorT& end_interface) {
1779
-  vector<AmDynInvoke*>::iterator cc_mod=cc_modules.begin();
1780
-
1781
-  for (CCInterfaceListIteratorT cc_it=call_profile.cc_interfaces.begin();
1782
-       cc_it != end_interface; cc_it++) {
1783
-    CCInterface& cc_if = *cc_it;
1784
-
1785
-    AmArg di_args,ret;
1786
-    di_args.push(cc_if.cc_name);
1787
-    di_args.push(getLocalTag());                 // call ltag
1788
-    di_args.push((AmObject*)&call_profile);
1789
-    di_args.push(AmArg());                       // timestamps
1790
-    di_args.back().push((int)call_start_ts.tv_sec);
1791
-    di_args.back().push((int)call_start_ts.tv_usec);
1792
-    di_args.back().push((int)call_connect_ts.tv_sec);
1793
-    di_args.back().push((int)call_connect_ts.tv_usec);
1794
-    di_args.back().push((int)call_end_ts.tv_sec);
1795
-    di_args.back().push((int)call_end_ts.tv_usec);
1796
-
1797
-    try {
1798
-      (*cc_mod)->invoke("end", di_args, ret);
1799
-    } catch (const AmArg::OutOfBoundsException& e) {
1800
-      ERROR("OutOfBoundsException executing call control interface end "
1801
-	    "module '%s' named '%s', parameters '%s'\n",
1802
-	    cc_if.cc_module.c_str(), cc_if.cc_name.c_str(),
1803
-	    AmArg::print(di_args).c_str());
1804
-    } catch (const AmArg::TypeMismatchException& e) {
1805
-      ERROR("TypeMismatchException executing call control interface end "
1806
-	    "module '%s' named '%s', parameters '%s'\n",
1807
-	    cc_if.cc_module.c_str(), cc_if.cc_name.c_str(),
1808
-	    AmArg::print(di_args).c_str());
1809
-    }
1810
-
1811
-    cc_mod++;
1812
-  }
1813
-}
1814
-
1815
-bool SBCDialog::updateLocalSdp(AmSdp &sdp)
1816
-{
1817
-  // remember transcodable payload IDs
1818
-  if (call_profile.transcoder.isActive())
1819
-    savePayloadIDs(sdp, MT_AUDIO, call_profile.transcoder.audio_codecs, transcoder_payload_mapping);
1820
-  return CallLeg::updateLocalSdp(sdp);
1821
-}
1822
-
1823
-bool SBCDialog::updateRemoteSdp(AmSdp &sdp)
1824
-{
1825
-  SBCRelayController rc(&call_profile.transcoder, true);
1826
-  if (call_profile.transcoder.isActive()) {
1827
-    if (media_session) return media_session->updateRemoteSdp(a_leg, sdp, &rc);
1828
-  }
1829
-
1830
-  // call original implementation because our special conditions above are not met
1831
-  return CallLeg::updateRemoteSdp(sdp);
1832
-}
1833
-
1834
-
1835
-
1836
-SBCCalleeSession::SBCCalleeSession(const SBCDialog* caller,
1837
-				   const SBCCallProfile& _call_profile)
1838
-  : auth(NULL),
1839
-    call_profile(_call_profile),
1840
-    CallLeg(caller)
1841
-{
1842
-  dlg.setRel100State(Am100rel::REL100_IGNORED);
1843
-
1844
-  if (!call_profile.contact.empty()) {
1845
-    dlg.contact_uri = SIP_HDR_COLSP(SIP_HDR_CONTACT) + call_profile.contact + CRLF;
1846
-  }
1847
-
1848
-  // moved from createCalleeSession
1849
-  
1850
-  if (call_profile.auth_enabled) {
1851
-    // adding auth handler
1852
-    AmSessionEventHandlerFactory* uac_auth_f = 
1853
-      AmPlugIn::instance()->getFactory4Seh("uac_auth");
1854
-    if (NULL == uac_auth_f)  {
1855
-      INFO("uac_auth module not loaded. uac auth NOT enabled.\n");
1856
-    } else {
1857
-      AmSessionEventHandler* h = uac_auth_f->getHandler(this);
1858
-      
1859
-      // we cannot use the generic AmSessionEventHandler hooks, 
1860
-      // because the hooks don't work in AmB2BSession
1861
-      setAuthHandler(h);
1862
-      DBG("uac auth enabled for callee session.\n");
1863
-    }
1864
-  }
1865
-
1866
-  if (call_profile.sst_enabled_value) {
1867
-    if (NULL == SBCFactory::session_timer_fact) {
1868
-      ERROR("session_timer module not loaded - unable to create call with SST\n");
1869
-      throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
1870
-    }
1871
-
1872
-    AmSessionEventHandler* h = SBCFactory::session_timer_fact->getHandler(this);
1873
-    if(!h) {
1874
-      ERROR("could not get a session timer event handler\n");
1875
-      throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
1876
-    }
1877
-
1878
-    if(h->configure(call_profile.sst_b_cfg)){
1879
-      ERROR("Could not configure the session timer: disabling session timers.\n");
1880
-      delete h;
1881
-    } else {
1882
-      addHandler(h);
1883
-    }
1884
-  }
1885
-
1886
-  if (!call_profile.outbound_proxy.empty()) {
1887
-    dlg.outbound_proxy = call_profile.outbound_proxy;
1888
-    dlg.force_outbound_proxy = call_profile.force_outbound_proxy;
1889
-  }
1890
-  
1891
-  if (!call_profile.next_hop.empty()) {
1892
-    dlg.next_hop = call_profile.next_hop;
1893
-  }
1894
-
1895
-  // was read from caller but reading directly from profile now
1896
-  if (call_profile.outbound_interface_value >= 0)
1897
-    dlg.outbound_interface = call_profile.outbound_interface_value;
1898
-  
1899
-  dlg.setOAEnabled(false); // ???
1900
-
1901
-  // was read from caller but reading directly from profile now
1902
-  if (call_profile.rtprelay_enabled || call_profile.transcoder.isActive()) {
1903
-    if (call_profile.rtprelay_interface_value >= 0)
1904
-      setRtpRelayInterface(call_profile.rtprelay_interface_value);
1905
-  }
1906
-
1907
-  setRtpRelayTransparentSeqno(call_profile.rtprelay_transparent_seqno);
1908
-  setRtpRelayTransparentSSRC(call_profile.rtprelay_transparent_ssrc);
1909
-
1910
-  // was read from caller but reading directly from profile now
1911
-  if (!call_profile.callid.empty()) dlg.callid = call_profile.callid;
1912
-  
1913
-}
1914
-
1915
-SBCCalleeSession::~SBCCalleeSession() {
1916
-  if (auth) 
1917
-    delete auth;
1918
-}
1919
-
1920
-void SBCCalleeSession::onDtmf(int event, int duration)
1921
-{
1922
-  if(media_session) {
1923
-    DBG("received DTMF on %c-leg (%i;%i)\n",
1924
-	a_leg ? 'A': 'B', event, duration);
1925
-    media_session->sendDtmf(!a_leg,event,duration);
1926
-  }
1927
-}
1928
-
1929
-inline UACAuthCred* SBCCalleeSession::getCredentials() {
1930
-  return &call_profile.auth_credentials;
1931
-}
1932
-
1933
-int SBCCalleeSession::relayEvent(AmEvent* ev)
1934
-{
1935
-    switch (ev->event_id) {
1936
-      case B2BSipRequest:
1937
-        {
1938
-          B2BSipRequestEvent* req_ev = dynamic_cast<B2BSipRequestEvent*>(ev);
1939
-
1940
-          if (isActiveFilter(call_profile.headerfilter)) {
1941
-            //B2BSipRequestEvent* req_ev = dynamic_cast<B2BSipRequestEvent*>(ev);
1942
-            // header filter
1943
-            assert(req_ev);
1944
-            inplaceHeaderFilter(req_ev->req.hdrs,
1945
-                call_profile.headerfilter_list, call_profile.headerfilter);
1946
-          }
1947
-
1948
-          DBG("filtering body for request '%s' (c/t '%s')\n",
1949
-              req_ev->req.method.c_str(), req_ev->req.body.getCTStr().c_str());
1950
-          // todo: handle filtering errors
1951
-
1952
-          AmSdp sdp;
1953
-          int res = filterBody(req_ev->req, sdp, call_profile, a_leg, transcoder_payload_mapping);
1954
-          if (res < 0) return res;
1955
-        }
1956
-        break;
1957
-
1958
-      case B2BSipReply:
1959
-        {
1960
-          B2BSipReplyEvent* reply_ev = dynamic_cast<B2BSipReplyEvent*>(ev);
1961
-
1962
-          if (isActiveFilter(call_profile.headerfilter) ||
1963
-              call_profile.reply_translations.size()) {
1964
-            assert(reply_ev);
1965
-            // header filter
1966
-            if (isActiveFilter(call_profile.headerfilter)) {
1967
-              inplaceHeaderFilter(reply_ev->reply.hdrs,
1968
-                  call_profile.headerfilter_list,
1969
-                  call_profile.headerfilter);
1970
-            }
1971
-
1972
-            // reply translations
1973
-            map<unsigned int, pair<unsigned int, string> >::iterator it =
1974