1 /*
2  * Copyright (C) 2002-2003 Fhg Fokus
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. This program is released under
10  * the GPL with the additional exemption that compiling, linking,
11  * and/or using OpenSSL is allowed.
12  *
13  * For a license to use the SEMS software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * SEMS is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 #include "AmB2BSession.h"
28 #include "AmSessionContainer.h"
29 #include "AmConfig.h"
30 #include "ampi/MonitoringAPI.h"
31 #include "AmSipHeaders.h"
32 #include "AmUtils.h"
33 #include "AmRtpReceiver.h"
34 
35 #include <assert.h>
36 
37 // helpers
38 static const string sdp_content_type(SIP_APPLICATION_SDP);
39 static const string empty;
40 
41 //
42 // helper functions
43 //
44 
errCode2RelayedReply(AmSipReply & reply,int err_code,unsigned default_code=500)45 static void errCode2RelayedReply(AmSipReply &reply, int err_code, unsigned default_code = 500)
46 {
47   // FIXME: use cleaner method to propagate error codes/reasons,
48   // do it everywhere in the code
49   if ((err_code < -399) && (err_code > -700)) {
50     reply.code = -err_code;
51   }
52   else reply.code = default_code;
53 
54   // TODO: optimize with a table
55   switch (reply.code) {
56     case 400: reply.reason = "Bad Request"; break;
57     case 478: reply.reason = "Unresolvable destination"; break;
58     case 488: reply.reason = SIP_REPLY_NOT_ACCEPTABLE_HERE; break;
59     default: reply.reason = SIP_REPLY_SERVER_INTERNAL_ERROR;
60   }
61 }
62 
63 //
64 // AmB2BSession methods
65 //
66 
AmB2BSession(const string & other_local_tag,AmSipDialog * p_dlg,AmSipSubscription * p_subs)67 AmB2BSession::AmB2BSession(const string& other_local_tag, AmSipDialog* p_dlg,
68 			   AmSipSubscription* p_subs)
69   : AmSession(p_dlg),
70     other_id(other_local_tag),
71     sip_relay_only(true),
72     est_invite_cseq(0),
73     est_invite_other_cseq(0),
74     est_invite_max_forwards(0),
75     subs(p_subs),
76     rtp_relay_mode(RTP_Direct),
77     rtp_relay_force_symmetric_rtp(false),
78     rtp_relay_transparent_seqno(true), rtp_relay_transparent_ssrc(true),
79     enable_dtmf_transcoding(false), enable_dtmf_rtp_filtering(false), enable_dtmf_rtp_detection(false),
80     media_session(NULL)
81 {
82   if(!subs) subs = new AmSipSubscription(dlg,this);
83 }
84 
~AmB2BSession()85 AmB2BSession::~AmB2BSession()
86 {
87   clearRtpReceiverRelay();
88 
89   DBG("relayed_req.size() = %zu\n",relayed_req.size());
90 
91   map<int,AmSipRequest>::iterator it = recvd_req.begin();
92   DBG("recvd_req.size() = %zu\n",recvd_req.size());
93   for(;it != recvd_req.end(); ++it){
94     DBG("  <%i,%s>\n",it->first,it->second.method.c_str());
95   }
96 
97   if(subs)
98     delete subs;
99 }
100 
set_sip_relay_only(bool r)101 void AmB2BSession::set_sip_relay_only(bool r) {
102   sip_relay_only = r;
103 
104   // disable offer/answer if we just relay requests
105   //dlg.setOAEnabled(!sip_relay_only); ???
106 }
107 
clear_other()108 void AmB2BSession::clear_other()
109 {
110   setOtherId("");
111 }
112 
process(AmEvent * event)113 void AmB2BSession::process(AmEvent* event)
114 {
115   B2BEvent* b2b_e = dynamic_cast<B2BEvent*>(event);
116   if(b2b_e){
117 
118     onB2BEvent(b2b_e);
119     return;
120   }
121 
122   SingleSubTimeoutEvent* to_ev = dynamic_cast<SingleSubTimeoutEvent*>(event);
123   if(to_ev) {
124     subs->onTimeout(to_ev->timer_id,to_ev->sub);
125     return;
126   }
127 
128   AmSession::process(event);
129 }
130 
finalize()131 void AmB2BSession::finalize()
132 {
133   // clean up relayed_req
134   if(!other_id.empty()) {
135     while(!relayed_req.empty()) {
136       TransMap::iterator it = relayed_req.begin();
137       const AmSipRequest& req = it->second;
138       relayError(req.method,req.cseq,true,481,SIP_REPLY_NOT_EXIST);
139       relayed_req.erase(it);
140     }
141   }
142 
143   AmSession::finalize();
144 }
145 
relayError(const string & method,unsigned cseq,bool forward,int err_code)146 void AmB2BSession::relayError(const string &method, unsigned cseq,
147 			      bool forward, int err_code)
148 {
149   if (method != "ACK") {
150     AmSipReply n_reply;
151     errCode2RelayedReply(n_reply, err_code, 500);
152     n_reply.cseq = cseq;
153     n_reply.cseq_method = method;
154     n_reply.from_tag = dlg->getLocalTag();
155     DBG("relaying B2B SIP error reply %u %s\n", n_reply.code, n_reply.reason.c_str());
156     relayEvent(new B2BSipReplyEvent(n_reply, forward, method, getLocalTag()));
157   }
158 }
159 
relayError(const string & method,unsigned cseq,bool forward,int sip_code,const char * reason)160 void AmB2BSession::relayError(const string &method, unsigned cseq, bool forward, int sip_code, const char *reason)
161 {
162   if (method != "ACK") {
163     AmSipReply n_reply;
164     n_reply.code = sip_code;
165     n_reply.reason = reason;
166     n_reply.cseq = cseq;
167     n_reply.cseq_method = method;
168     n_reply.from_tag = dlg->getLocalTag();
169     DBG("relaying B2B SIP reply %d %s\n", sip_code, reason);
170     relayEvent(new B2BSipReplyEvent(n_reply, forward, method, getLocalTag()));
171   }
172 }
173 
onB2BEvent(B2BEvent * ev)174 void AmB2BSession::onB2BEvent(B2BEvent* ev)
175 {
176   DBG("AmB2BSession::onB2BEvent\n");
177   switch(ev->event_id){
178 
179   case B2BSipRequest:
180     {
181       B2BSipRequestEvent* req_ev = dynamic_cast<B2BSipRequestEvent*>(ev);
182       assert(req_ev);
183 
184       DBG("B2BSipRequest: %s (fwd=%s)\n",
185 	  req_ev->req.method.c_str(),
186 	  req_ev->forward?"true":"false");
187 
188       if(req_ev->forward){
189 
190 	// Check Max-Forwards first
191 	if(req_ev->req.max_forwards == 0) {
192 	  relayError(req_ev->req.method,req_ev->req.cseq,
193 		     true,483,SIP_REPLY_TOO_MANY_HOPS);
194 	  return;
195 	};
196 
197 	if (req_ev->req.method == SIP_METH_INVITE &&
198 	    dlg->getUACInvTransPending()) {
199 	  // don't relay INVITE if INV trans pending
200 	  DBG("not sip-relaying INVITE with pending INV transaction, "
201 	      "b2b-relaying 491 pending\n");
202           relayError(req_ev->req.method, req_ev->req.cseq,
203 		     true, 491, SIP_REPLY_PENDING);
204 	  return;
205 	}
206 
207 	if (req_ev->req.method == SIP_METH_BYE &&
208 	    dlg->getStatus() != AmBasicSipDialog::Connected) {
209 	  DBG("not sip-relaying BYE in not connected dlg, b2b-relaying 200 OK\n");
210           relayError(req_ev->req.method, req_ev->req.cseq,
211 		     true, 200, "OK");
212 	  return;
213 	}
214       }
215 
216        if( (req_ev->req.method == SIP_METH_BYE)
217 	  // CANCEL is handled differently: other side has already
218 	  // sent a terminate event.
219 	  //|| (req_ev->req.method == SIP_METH_CANCEL)
220 	  ) {
221 
222 	 if (onOtherBye(req_ev->req))
223 	   req_ev->processed = true; // app should have relayed 200 to BYE
224       }
225 
226       if(req_ev->forward && !req_ev->processed){
227         int res = relaySip(req_ev->req);
228 	if(res < 0) {
229 	  // reply relayed request internally
230           relayError(req_ev->req.method, req_ev->req.cseq, true, res);
231 	  return;
232 	}
233       }
234 
235     }
236     return;
237 
238   case B2BSipReply:
239     {
240       B2BSipReplyEvent* reply_ev = dynamic_cast<B2BSipReplyEvent*>(ev);
241       assert(reply_ev);
242 
243       DBG("B2BSipReply: %i %s (fwd=%s)\n",reply_ev->reply.code,
244 	  reply_ev->reply.reason.c_str(),reply_ev->forward?"true":"false");
245       DBG("B2BSipReply: content-type = %s\n",
246 	  reply_ev->reply.body.getCTStr().c_str());
247 
248       if(reply_ev->forward){
249 
250         std::map<int,AmSipRequest>::iterator t_req =
251 	  recvd_req.find(reply_ev->reply.cseq);
252 
253 	if (t_req != recvd_req.end()) {
254 	  if ((reply_ev->reply.code >= 300) && (reply_ev->reply.code <= 305) &&
255 	      !reply_ev->reply.contact.empty()) {
256 	    // relay with Contact in 300 - 305 redirect messages
257 	    AmSipReply n_reply(reply_ev->reply);
258 	    n_reply.hdrs+=SIP_HDR_COLSP(SIP_HDR_CONTACT) +
259 	      reply_ev->reply.contact+ CRLF;
260 
261 	    if(relaySip(t_req->second,n_reply) < 0) {
262 	      terminateOtherLeg();
263 	      terminateLeg();
264 	    }
265 	  } else {
266 	    // relay response
267 	    if(relaySip(t_req->second,reply_ev->reply) < 0) {
268 	      terminateOtherLeg();
269 	      terminateLeg();
270 	    }
271 	  }
272 
273 	} else {
274 	  DBG("Cannot relay reply: request already replied"
275 	      " (code=%u;cseq=%u;call-id=%s)",
276 	      reply_ev->reply.code, reply_ev->reply.cseq,
277 	      reply_ev->reply.callid.c_str());
278 	}
279       } else {
280 	// check whether not-forwarded (locally initiated)
281 	// INV/UPD transaction changed session in other leg
282 	if (SIP_IS_200_CLASS(reply_ev->reply.code) &&
283 	    (!reply_ev->reply.body.empty()) &&
284 	    (reply_ev->reply.cseq_method == SIP_METH_INVITE ||
285 	     reply_ev->reply.cseq_method == SIP_METH_UPDATE)) {
286 	  if (updateSessionDescription(reply_ev->reply.body)) {
287 	    if (reply_ev->reply.cseq != est_invite_cseq) {
288 	      if (dlg->getUACInvTransPending()) {
289 		DBG("changed session, but UAC INVITE trans pending\n");
290 		// todo(?): save until trans is finished?
291 		return;
292 	      }
293 	      DBG("session description changed - refreshing\n");
294 	      sendEstablishedReInvite();
295 	    } else {
296 	      DBG("reply to establishing INVITE request - not refreshing\n");
297 	    }
298 	  }
299 	}
300       }
301     }
302     return;
303 
304   case B2BTerminateLeg:
305     DBG("terminateLeg()\n");
306     terminateLeg();
307     break;
308   }
309 
310   //ERROR("unknown event caught\n");
311 }
312 
getMappedReferID(unsigned int refer_id,unsigned int & mapped_id) const313 bool AmB2BSession::getMappedReferID(unsigned int refer_id,
314 				    unsigned int& mapped_id) const
315 {
316   map<unsigned int, unsigned int>::const_iterator id_it =
317     refer_id_map.find(refer_id);
318   if(id_it != refer_id_map.end()) {
319     mapped_id = id_it->second;
320     return true;
321   }
322 
323   return false;
324 }
325 
insertMappedReferID(unsigned int refer_id,unsigned int mapped_id)326 void AmB2BSession::insertMappedReferID(unsigned int refer_id,
327 				       unsigned int mapped_id)
328 {
329   refer_id_map[refer_id] = mapped_id;
330 }
331 
onSipRequest(const AmSipRequest & req)332 void AmB2BSession::onSipRequest(const AmSipRequest& req)
333 {
334   bool fwd = sip_relay_only &&
335     (req.method != SIP_METH_CANCEL);
336 
337   if( ((req.method == SIP_METH_SUBSCRIBE) ||
338        (req.method == SIP_METH_NOTIFY) ||
339        (req.method == SIP_METH_REFER))
340       && !subs->onRequestIn(req) ) {
341     return;
342   }
343 
344   if(!fwd)
345     AmSession::onSipRequest(req);
346   else {
347     updateRefreshMethod(req.hdrs);
348 
349     if(req.method == SIP_METH_BYE)
350       onBye(req);
351   }
352 
353   B2BSipRequestEvent* r_ev = new B2BSipRequestEvent(req,fwd);
354 
355   if (fwd) {
356     DBG("relaying B2B SIP request (fwd) %s %s\n", r_ev->req.method.c_str(), r_ev->req.r_uri.c_str());
357 
358     if(r_ev->req.method == SIP_METH_NOTIFY) {
359 
360       string event = getHeader(r_ev->req.hdrs,SIP_HDR_EVENT,true);
361       string id = get_header_param(event,"id");
362       event = strip_header_params(event);
363 
364       if(event == "refer" && !id.empty()) {
365 
366 	int id_int=0;
367 	if(str2int(id,id_int)) {
368 
369 	  unsigned int mapped_id=0;
370 	  if(getMappedReferID(id_int,mapped_id)) {
371 
372 	    removeHeader(r_ev->req.hdrs,SIP_HDR_EVENT);
373 	    r_ev->req.hdrs += SIP_HDR_COLSP(SIP_HDR_EVENT) "refer;id="
374 	      + int2str(mapped_id) + CRLF;
375 	  }
376 	}
377       }
378     }
379 
380     int res = relayEvent(r_ev);
381     if (res == 0) {
382       // successfuly relayed, store the request
383       if(req.method != SIP_METH_ACK)
384         recvd_req.insert(std::make_pair(req.cseq,req));
385     }
386     else {
387       // relay failed, generate error reply
388       DBG("relay failed, replying error\n");
389       AmSipReply n_reply;
390       errCode2RelayedReply(n_reply, res, 500);
391       dlg->reply(req, n_reply.code, n_reply.reason);
392     }
393 
394     return;
395   }
396 
397   DBG("relaying B2B SIP request %s %s\n", r_ev->req.method.c_str(), r_ev->req.r_uri.c_str());
398   relayEvent(r_ev);
399 }
400 
onRequestSent(const AmSipRequest & req)401 void AmB2BSession::onRequestSent(const AmSipRequest& req)
402 {
403   if( ((req.method == SIP_METH_SUBSCRIBE) ||
404        (req.method == SIP_METH_NOTIFY) ||
405        (req.method == SIP_METH_REFER)) ) {
406     subs->onRequestSent(req);
407   }
408 
409   AmSession::onRequestSent(req);
410 }
411 
updateLocalSdp(AmSdp & sdp)412 void AmB2BSession::updateLocalSdp(AmSdp &sdp)
413 {
414   if (rtp_relay_mode == RTP_Direct) return; // nothing to do
415 
416   if (!media_session) {
417     // report missing media session (here we get for rtp_relay_mode == RTP_Relay)
418     ERROR("BUG: media session is missing, can't update local SDP\n");
419     return; // FIXME: throw an exception here?
420   }
421 
422   media_session->replaceConnectionAddress(sdp, a_leg, localMediaIP(), advertisedIP());
423 }
424 
updateLocalBody(AmMimeBody & body)425 void AmB2BSession::updateLocalBody(AmMimeBody& body)
426 {
427   AmMimeBody *sdp = body.hasContentType(SIP_APPLICATION_SDP);
428   if (!sdp) return;
429 
430   AmSdp parser_sdp;
431   if (parser_sdp.parse((const char*)sdp->getPayload())) {
432     DBG("SDP parsing failed!\n");
433     return; // FIXME: throw an exception here?
434   }
435 
436   updateLocalSdp(parser_sdp);
437 
438   // regenerate SDP
439   string n_body;
440   parser_sdp.print(n_body);
441   sdp->parse(sdp->getCTStr(), (const unsigned char*)n_body.c_str(), n_body.length());
442 }
443 
updateUACTransCSeq(unsigned int old_cseq,unsigned int new_cseq)444 void AmB2BSession::updateUACTransCSeq(unsigned int old_cseq, unsigned int new_cseq) {
445   if (old_cseq == new_cseq)
446     return;
447 
448   TransMap::iterator t = relayed_req.find(old_cseq);
449   if (t != relayed_req.end()) {
450     relayed_req[new_cseq] = t->second;
451     relayed_req.erase(t);
452     DBG("updated relayed_req (UAC trans): CSeq %u -> %u\n", old_cseq, new_cseq);
453   }
454 
455   if (est_invite_cseq == old_cseq) {
456     est_invite_cseq = new_cseq;
457     DBG("updated est_invite_cseq: CSeq %u -> %u\n", old_cseq, new_cseq);
458   }
459 }
460 
461 
onSipReply(const AmSipRequest & req,const AmSipReply & reply,AmBasicSipDialog::Status old_dlg_status)462 void AmB2BSession::onSipReply(const AmSipRequest& req, const AmSipReply& reply,
463 			      AmBasicSipDialog::Status old_dlg_status)
464 {
465   TransMap::iterator t = relayed_req.find(reply.cseq);
466   bool fwd = (t != relayed_req.end()) && (reply.code != 100);
467 
468   DBG("onSipReply: %s -> %i %s (fwd=%s), c-t=%s\n",
469       reply.cseq_method.c_str(), reply.code,reply.reason.c_str(),
470       fwd?"true":"false",reply.body.getCTStr().c_str());
471 
472   if(!dlg->getRemoteTag().empty() && dlg->getRemoteTag() != reply.to_tag) {
473     DBG("sess %p received %i reply with != to-tag: %s (remote-tag:%s)",
474 	this, reply.code, reply.to_tag.c_str(),dlg->getRemoteTag().c_str());
475     return; // drop packet
476   }
477 
478   if( ((reply.cseq_method == SIP_METH_SUBSCRIBE) ||
479        (reply.cseq_method == SIP_METH_NOTIFY) ||
480        (reply.cseq_method == SIP_METH_REFER))
481       && !subs->onReplyIn(req,reply) ) {
482     DBG("subs.onReplyIn returned false\n");
483     return;
484   }
485 
486   if(fwd) {
487     updateRefreshMethod(reply.hdrs);
488 
489     AmSipReply n_reply = reply;
490     n_reply.cseq = t->second.cseq;
491 
492     DBG("relaying B2B SIP reply %u %s\n", n_reply.code, n_reply.reason.c_str());
493     relayEvent(new B2BSipReplyEvent(n_reply, true, t->second.method, getLocalTag()));
494 
495     if(reply.code >= 200) {
496       if ((reply.code < 300) && (t->second.method == SIP_METH_INVITE)) {
497 	DBG("not removing relayed INVITE transaction yet...\n");
498       } else {
499 	//grab cseq-mqpping in case of REFER
500 	if((reply.code < 300) && (reply.cseq_method == SIP_METH_REFER)) {
501 	  if(subs->subscriptionExists(SingleSubscription::Subscriber,
502 				      "refer",int2str(reply.cseq))) {
503 	    // remember mapping for refer event package event-id
504 	    insertMappedReferID(reply.cseq,t->second.cseq);
505 	  }
506 	}
507 	relayed_req.erase(t);
508       }
509     }
510   } else {
511     AmSession::onSipReply(req, reply, old_dlg_status);
512 
513     AmSipReply n_reply = reply;
514     if(est_invite_cseq == reply.cseq){
515       n_reply.cseq = est_invite_other_cseq;
516     }
517     else {
518       // correct CSeq for 100 on relayed request (FIXME: why not relayed above?)
519       if (t != relayed_req.end()) n_reply.cseq = t->second.cseq;
520       else {
521         // the reply here will not have the proper cseq for the other side.
522         // We should avoid collisions of CSeqs - painful in comparsions with
523         // est_invite_cseq where are compared CSeq numbers in different
524         // directions. Under presumption that 0 is not used we can use it
525         // as 'unspecified cseq' (according to RFC 3261 this seems to be valid
526         // value so it need not to work always)
527         n_reply.cseq = 0;
528       }
529     }
530     DBG("relaying B2B SIP reply %u %s\n", n_reply.code, n_reply.reason.c_str());
531     relayEvent(new B2BSipReplyEvent(n_reply, false, reply.cseq_method, getLocalTag()));
532   }
533 }
534 
onReplySent(const AmSipRequest & req,const AmSipReply & reply)535 void AmB2BSession::onReplySent(const AmSipRequest& req, const AmSipReply& reply)
536 {
537   if( ((reply.cseq_method == SIP_METH_SUBSCRIBE) ||
538        (reply.cseq_method == SIP_METH_NOTIFY) ||
539        (reply.cseq_method == SIP_METH_REFER)) ) {
540     subs->onReplySent(req,reply);
541   }
542 
543   if(reply.code >= 200 && reply.cseq_method != SIP_METH_CANCEL){
544     if((req.method == SIP_METH_INVITE) && (reply.code >= 300)) {
545       DBG("relayed INVITE failed with %u %s\n", reply.code, reply.reason.c_str());
546     }
547     DBG("recvd_req.erase(<%u,%s>)\n", req.cseq, req.method.c_str());
548     recvd_req.erase(reply.cseq);
549   }
550 
551   AmSession::onReplySent(req,reply);
552 }
553 
onInvite2xx(const AmSipReply & reply)554 void AmB2BSession::onInvite2xx(const AmSipReply& reply)
555 {
556   TransMap::iterator it = relayed_req.find(reply.cseq);
557   bool req_fwded = it != relayed_req.end();
558   if(!req_fwded) {
559     DBG("req not fwded\n");
560     AmSession::onInvite2xx(reply);
561   } else {
562     DBG("no 200 ACK now: waiting for the 200 ACK from the other side...\n");
563   }
564 }
565 
onSdpCompleted(const AmSdp & local_sdp,const AmSdp & remote_sdp)566 int AmB2BSession::onSdpCompleted(const AmSdp& local_sdp, const AmSdp& remote_sdp)
567 {
568   if (rtp_relay_mode != RTP_Direct) {
569     if (!media_session) {
570       // report missing media session (here we get for rtp_relay_mode == RTP_Relay)
571       ERROR("BUG: media session is missing, can't update SDP\n");
572     }
573     else {
574       media_session->updateStreams(a_leg, local_sdp, remote_sdp, this);
575     }
576   }
577 
578   if(hasRtpStream() && RTPStream()->getSdpMediaIndex() >= 0) {
579     if(!sip_relay_only){
580       return AmSession::onSdpCompleted(local_sdp,remote_sdp);
581     }
582     DBG("sip_relay_only = true: doing nothing!\n");
583   }
584 
585   return 0;
586 }
587 
relayEvent(AmEvent * ev)588 int AmB2BSession::relayEvent(AmEvent* ev)
589 {
590   DBG("AmB2BSession::relayEvent: to other_id='%s'\n",
591       other_id.c_str());
592 
593   if(!other_id.empty()) {
594     if (!AmSessionContainer::instance()->postEvent(other_id,ev))
595       return -1;
596   } else {
597     delete ev;
598   }
599 
600   return 0;
601 }
602 
onOtherBye(const AmSipRequest & req)603 bool AmB2BSession::onOtherBye(const AmSipRequest& req)
604 {
605   DBG("onOtherBye()\n");
606 
607   // don't call terminateLeg(), as BYE will be sent end-to-end
608   setStopped();
609   clearRtpReceiverRelay();
610 
611   return false;
612 }
613 
onOtherReply(const AmSipReply & reply)614 bool AmB2BSession::onOtherReply(const AmSipReply& reply)
615 {
616   if(reply.code >= 300)
617     setStopped();
618 
619   return false;
620 }
621 
terminateLeg()622 void AmB2BSession::terminateLeg()
623 {
624   setStopped();
625 
626   clearRtpReceiverRelay();
627 
628   dlg->bye("", SIP_FLAGS_VERBATIM);
629 }
630 
terminateOtherLeg()631 void AmB2BSession::terminateOtherLeg()
632 {
633   if (!other_id.empty())
634     relayEvent(new B2BEvent(B2BTerminateLeg));
635 }
636 
onRtpTimeout()637 void AmB2BSession::onRtpTimeout() {
638   DBG("RTP Timeout, ending other leg\n");
639   terminateOtherLeg();
640   AmSession::onRtpTimeout();
641 }
642 
onSessionTimeout()643 void AmB2BSession::onSessionTimeout() {
644   DBG("Session Timer: Timeout, ending other leg\n");
645   terminateOtherLeg();
646   AmSession::onSessionTimeout();
647 }
648 
onRemoteDisappeared(const AmSipReply & reply)649 void AmB2BSession::onRemoteDisappeared(const AmSipReply& reply) {
650   if (dlg && dlg->getStatus() == AmBasicSipDialog::Connected) {
651     DBG("%c leg: remote unreachable, ending other leg\n", a_leg?'A':'B');
652     terminateOtherLeg();
653     AmSession::onRemoteDisappeared(reply);
654   }
655 }
656 
onNoAck(unsigned int cseq)657 void AmB2BSession::onNoAck(unsigned int cseq)
658 {
659   DBG("OnNoAck(%u): terminate other leg.\n",cseq);
660   terminateOtherLeg();
661   AmSession::onNoAck(cseq);
662 }
663 
saveSessionDescription(const AmMimeBody & body)664 bool AmB2BSession::saveSessionDescription(const AmMimeBody& body) {
665 
666   const AmMimeBody* sdp_body = body.hasContentType(SIP_APPLICATION_SDP);
667   if(!sdp_body)
668     return false;
669 
670   DBG("saving session description (%s, %.*s...)\n",
671       sdp_body->getCTStr().c_str(), 50, sdp_body->getPayload());
672 
673   established_body = *sdp_body;
674 
675   const char* cmp_body_begin = (const char*)sdp_body->getPayload();
676   size_t cmp_body_length = sdp_body->getLen();
677 
678 #define skip_line						\
679     while (cmp_body_length && *cmp_body_begin != '\n') {	\
680       cmp_body_begin++;						\
681       cmp_body_length--;					\
682     }								\
683     if (cmp_body_length) {					\
684       cmp_body_begin++;						\
685       cmp_body_length--;					\
686     }
687 
688   if (cmp_body_length) {
689   // for SDP, skip v and o line
690   // (o might change even if SDP unchanged)
691   skip_line;
692   skip_line;
693   }
694 
695   body_hash = hashlittle(cmp_body_begin, cmp_body_length, 0);
696   return true;
697 }
698 
updateSessionDescription(const AmMimeBody & body)699 bool AmB2BSession::updateSessionDescription(const AmMimeBody& body) {
700 
701   const AmMimeBody* sdp_body = body.hasContentType(SIP_APPLICATION_SDP);
702   if(!sdp_body)
703     return false;
704 
705   const char* cmp_body_begin = (const char*)sdp_body->getPayload();
706   size_t cmp_body_length = sdp_body->getLen();
707   if (cmp_body_length) {
708     // for SDP, skip v and o line
709     // (o might change even if SDP unchanged)
710     skip_line;
711     skip_line;
712   }
713 
714 #undef skip_line
715 
716   uint32_t new_body_hash = hashlittle(cmp_body_begin, cmp_body_length, 0);
717 
718   if (body_hash != new_body_hash) {
719     DBG("session description changed - saving (%s, %.*s...)\n",
720 	sdp_body->getCTStr().c_str(), 50, sdp_body->getPayload());
721     body_hash = new_body_hash;
722     established_body = body;
723     return true;
724   }
725 
726   return false;
727 }
728 
sendEstablishedReInvite()729 int AmB2BSession::sendEstablishedReInvite() {
730   if (established_body.empty()) {
731     ERROR("trying to re-INVITE with saved description, but none saved\n");
732     return -1;
733   }
734 
735   DBG("sending re-INVITE with saved session description\n");
736 
737   try {
738     AmMimeBody body(established_body); // contains only SDP
739     updateLocalBody(body);
740     return dlg->reinvite("", &body, SIP_FLAGS_VERBATIM);
741   } catch (const string& s) {
742     ERROR("sending established SDP reinvite: %s\n", s.c_str());
743   }
744   return -1;
745 }
746 
refresh(int flags)747 bool AmB2BSession::refresh(int flags) {
748   // no session refresh if not connected
749   if (dlg->getStatus() != AmSipDialog::Connected)
750     return false;
751 
752   DBG(" AmB2BSession::refresh: refreshing session\n");
753   // not in B2B mode
754   if (other_id.empty() ||
755       // UPDATE as refresh handled like normal session
756       refresh_method == REFRESH_UPDATE) {
757     return AmSession::refresh(SIP_FLAGS_VERBATIM);
758   }
759 
760   // refresh with re-INVITE
761   if (dlg->getUACInvTransPending()) {
762     DBG("INVITE transaction pending - not refreshing now\n");
763     return false;
764   }
765   return sendEstablishedReInvite() == 0;
766 }
767 
relaySip(const AmSipRequest & req)768 int AmB2BSession::relaySip(const AmSipRequest& req)
769 {
770   AmMimeBody body(req.body);
771 
772   if ((req.method == SIP_METH_INVITE ||
773        req.method == SIP_METH_UPDATE ||
774        req.method == SIP_METH_ACK ||
775        req.method == SIP_METH_PRACK))
776   {
777     updateLocalBody(body);
778   }
779 
780   if (req.method != "ACK") {
781     relayed_req[dlg->cseq] = req;
782 
783     const string* hdrs = &req.hdrs;
784     string m_hdrs;
785 
786     // translate RAck for PRACK
787     if (req.method == SIP_METH_PRACK && req.rseq) {
788       TransMap::iterator t;
789       for (t=relayed_req.begin(); t != relayed_req.end(); t++) {
790 	if (t->second.cseq == req.rack_cseq) {
791 	  m_hdrs = req.hdrs +
792 	    SIP_HDR_COLSP(SIP_HDR_RACK) + int2str(req.rseq) +
793 	    " " + int2str(t->first) + " " + req.rack_method + CRLF;
794 	  hdrs = &m_hdrs;
795 	  break;
796 	}
797       }
798       if (t==relayed_req.end()) {
799 	WARN("Transaction with CSeq %d not found for translating RAck cseq\n",
800 	     req.rack_cseq);
801       }
802     }
803 
804     DBG("relaying SIP request %s %s %d\n", req.method.c_str(),
805 	req.r_uri.c_str(), req.max_forwards - 1);
806 
807     int err = dlg->sendRequest(req.method, &body, *hdrs, SIP_FLAGS_VERBATIM,
808 			       req.max_forwards - 1);
809     if(err < 0){
810       ERROR("dlg->sendRequest() failed\n");
811       return err;
812     }
813 
814     if ((req.method == SIP_METH_INVITE ||
815 	 req.method == SIP_METH_UPDATE) &&
816 	!req.body.empty()) {
817       saveSessionDescription(req.body);
818     }
819 
820   } else {
821     //its a (200) ACK
822     TransMap::iterator t = relayed_req.begin();
823 
824     while (t != relayed_req.end()) {
825       if (t->second.cseq == req.cseq)
826 	break;
827       t++;
828     }
829     if (t == relayed_req.end()) {
830       ERROR("transaction for ACK not found in relayed requests\n");
831       // FIXME: local body (if updated) should be discarded here
832       return -1;
833     }
834 
835     DBG("sending relayed 200 ACK\n");
836     int err = dlg->send_200_ack(t->first, &body,
837 			       req.hdrs, SIP_FLAGS_VERBATIM);
838     if(err < 0) {
839       ERROR("dlg->send_200_ack() failed\n");
840       return err;
841     }
842 
843     if (!req.body.empty() &&
844 	(t->second.method == SIP_METH_INVITE)) {
845     // delayed SDP negotiation - save SDP
846       saveSessionDescription(req.body);
847     }
848 
849     relayed_req.erase(t);
850   }
851 
852   return 0;
853 }
854 
relaySip(const AmSipRequest & orig,const AmSipReply & reply)855 int AmB2BSession::relaySip(const AmSipRequest& orig, const AmSipReply& reply)
856 {
857   const string* hdrs = &reply.hdrs;
858   string m_hdrs;
859   const string method(orig.method);
860 
861   if (reply.rseq != 0) {
862     m_hdrs = reply.hdrs +
863       SIP_HDR_COLSP(SIP_HDR_RSEQ) + int2str(reply.rseq) + CRLF;
864     hdrs = &m_hdrs;
865   }
866 
867   AmMimeBody body(reply.body);
868   if ((orig.method == SIP_METH_INVITE ||
869        orig.method == SIP_METH_UPDATE ||
870        orig.method == SIP_METH_ACK ||
871        orig.method == SIP_METH_PRACK))
872   {
873     updateLocalBody(body);
874   }
875 
876   DBG("relaying SIP reply %u %s\n", reply.code, reply.reason.c_str());
877 
878   int flags = SIP_FLAGS_VERBATIM;
879   if(reply.to_tag.empty())
880     flags |= SIP_FLAGS_NOTAG;
881 
882   int err = dlg->reply(orig,reply.code,reply.reason,
883 		       &body, *hdrs, flags);
884 
885   if(err < 0){
886     ERROR("dlg->reply() failed\n");
887     return err;
888   }
889 
890   if ((method == SIP_METH_INVITE ||
891        method == SIP_METH_UPDATE) &&
892       !reply.body.empty()) {
893     saveSessionDescription(reply.body);
894   }
895 
896   return 0;
897 }
898 
setRtpRelayMode(RTPRelayMode mode)899 void AmB2BSession::setRtpRelayMode(RTPRelayMode mode)
900 {
901   DBG("enabled RTP relay mode for B2B call '%s'\n",
902       getLocalTag().c_str());
903 
904   rtp_relay_mode = mode;
905 }
906 
setRtpInterface(int relay_interface)907 void AmB2BSession::setRtpInterface(int relay_interface) {
908   DBG("setting RTP interface for session '%s' to %i\n",
909       getLocalTag().c_str(), relay_interface);
910   rtp_interface = relay_interface;
911 }
912 
setRtpRelayForceSymmetricRtp(bool force_symmetric)913 void AmB2BSession::setRtpRelayForceSymmetricRtp(bool force_symmetric) {
914   rtp_relay_force_symmetric_rtp = force_symmetric;
915 }
916 
setRtpRelayTransparentSeqno(bool transparent)917 void AmB2BSession::setRtpRelayTransparentSeqno(bool transparent) {
918   rtp_relay_transparent_seqno = transparent;
919 }
920 
setRtpRelayTransparentSSRC(bool transparent)921 void AmB2BSession::setRtpRelayTransparentSSRC(bool transparent) {
922   rtp_relay_transparent_ssrc = transparent;
923 }
924 
setEnableDtmfTranscoding(bool enable)925 void AmB2BSession::setEnableDtmfTranscoding(bool enable) {
926   enable_dtmf_transcoding = enable;
927 }
928 
setEnableDtmfRtpFiltering(bool enable)929 void AmB2BSession::setEnableDtmfRtpFiltering(bool enable) {
930   enable_dtmf_rtp_filtering = enable;
931 }
932 
setEnableDtmfRtpDetection(bool enable)933 void AmB2BSession::setEnableDtmfRtpDetection(bool enable) {
934   enable_dtmf_rtp_detection = enable;
935 }
936 
getLowFiPLs(vector<SdpPayload> & lowfi_payloads) const937 void AmB2BSession::getLowFiPLs(vector<SdpPayload>& lowfi_payloads) const {
938   lowfi_payloads = this->lowfi_payloads;
939 }
940 
setLowFiPLs(const vector<SdpPayload> & lowfi_payloads)941 void AmB2BSession::setLowFiPLs(const vector<SdpPayload>& lowfi_payloads) {
942   this->lowfi_payloads = lowfi_payloads;
943 }
944 
clearRtpReceiverRelay()945 void AmB2BSession::clearRtpReceiverRelay() {
946   switch (rtp_relay_mode) {
947 
948     case RTP_Relay:
949     case RTP_Transcoding:
950       if (media_session) {
951         media_session->stop(a_leg);
952         media_session->releaseReference();
953         media_session = NULL;
954       }
955       break;
956 
957     case RTP_Direct:
958       // nothing to do
959       break;
960   }
961 }
962 
computeRelayMask(const SdpMedia & m,bool & enable,PayloadMask & mask)963 void AmB2BSession::computeRelayMask(const SdpMedia &m, bool &enable, PayloadMask &mask)
964 {
965   int te_pl = -1;
966   enable = false;
967 
968   mask.clear();
969 
970   // walk through the media lines and find the telephone-event payload
971   for (std::vector<SdpPayload>::const_iterator i = m.payloads.begin();
972       i != m.payloads.end(); ++i)
973   {
974     // do not mark telephone-event payload for relay
975     if(!strcasecmp("telephone-event",i->encoding_name.c_str())){
976       te_pl = i->payload_type;
977     }
978     else {
979       enable = true;
980     }
981   }
982 
983   if(!enable)
984     return;
985 
986   if(te_pl > 0) {
987     DBG("unmarking telephone-event payload %d for relay\n", te_pl);
988     mask.set(te_pl);
989   }
990 
991   DBG("marking all other payloads for relay\n");
992   mask.invert();
993 }
994 
995 
996 //
997 // AmB2BCallerSession methods
998 //
999 
AmB2BCallerSession()1000 AmB2BCallerSession::AmB2BCallerSession()
1001   : AmB2BSession(),
1002     callee_status(None), sip_relay_early_media_sdp(false)
1003 {
1004   a_leg = true;
1005 }
1006 
~AmB2BCallerSession()1007 AmB2BCallerSession::~AmB2BCallerSession()
1008 {
1009 }
1010 
set_sip_relay_early_media_sdp(bool r)1011 void AmB2BCallerSession::set_sip_relay_early_media_sdp(bool r)
1012 {
1013   sip_relay_early_media_sdp = r;
1014 }
1015 
terminateLeg()1016 void AmB2BCallerSession::terminateLeg()
1017 {
1018   AmB2BSession::terminateLeg();
1019 }
1020 
terminateOtherLeg()1021 void AmB2BCallerSession::terminateOtherLeg()
1022 {
1023   AmB2BSession::terminateOtherLeg();
1024   callee_status = None;
1025 }
1026 
onB2BEvent(B2BEvent * ev)1027 void AmB2BCallerSession::onB2BEvent(B2BEvent* ev)
1028 {
1029   bool processed = false;
1030 
1031   if(ev->event_id == B2BSipReply){
1032 
1033     AmSipReply& reply = ((B2BSipReplyEvent*)ev)->reply;
1034 
1035     if(getOtherId().empty()){
1036       //DBG("Discarding B2BSipReply from other leg (other_id empty)\n");
1037       DBG("B2BSipReply: other_id empty ("
1038 	  "reply code=%i; method=%s; callid=%s; from_tag=%s; "
1039 	  "to_tag=%s; cseq=%i)\n",
1040 	  reply.code,reply.cseq_method.c_str(),reply.callid.c_str(),reply.from_tag.c_str(),
1041 	  reply.to_tag.c_str(),reply.cseq);
1042       //return;
1043     }
1044     else if(getOtherId() != reply.from_tag){// was: local_tag
1045       DBG("Dialog mismatch! (oi=%s;ft=%s)\n",
1046 	  getOtherId().c_str(),reply.from_tag.c_str());
1047       return;
1048     }
1049 
1050     DBG("%u %s reply received from other leg\n", reply.code, reply.reason.c_str());
1051 
1052     switch(callee_status){
1053     case NoReply:
1054     case Ringing:
1055       if (reply.cseq == invite_req.cseq) {
1056 
1057 	if (reply.code < 200) {
1058 
1059 	  if ((!sip_relay_only) &&
1060 	      (reply.code>=180 && reply.code<=183 && (!reply.body.empty()))) {
1061 	    // save early media SDP
1062 	    updateSessionDescription(reply.body);
1063 
1064 	    if (sip_relay_early_media_sdp) {
1065 	      if (reinviteCaller(reply)) {
1066 		ERROR("re-INVITEing caller for early session failed - "
1067 		      "stopping this and other leg\n");
1068 		terminateOtherLeg();
1069 		terminateLeg();
1070 		break;
1071 	      }
1072 	    }
1073 
1074 	  }
1075 
1076 	  callee_status = Ringing;
1077 
1078 	} else if(reply.code < 300){
1079 
1080 	  callee_status  = Connected;
1081 	  DBG("setting callee status to connected\n");
1082 	  if (!sip_relay_only) {
1083 	    DBG("received 200 class reply to establishing INVITE: "
1084 		"switching to SIP relay only mode, sending re-INVITE to caller\n");
1085 	    sip_relay_only = true;
1086 	    AmSipReply n_reply = reply;
1087 
1088 	    if (n_reply.body.empty() && !established_body.empty()) {
1089 	      DBG("callee FR without SDP, using provisional response's (18x) one\n");
1090 	      n_reply.body = established_body;
1091 	    }
1092 
1093 	    if (reinviteCaller(n_reply)) {
1094 	      ERROR("re-INVITEing caller failed - stopping this and other leg\n");
1095 	      terminateOtherLeg();
1096 	      terminateLeg();
1097 	    }
1098 	  }
1099 	} else {
1100 	  // 	DBG("received %i from other leg: other_id=%s; reply.local_tag=%s\n",
1101 	  // 	    reply.code,other_id.c_str(),reply.local_tag.c_str());
1102 
1103 	  // TODO: terminated my own leg instead? (+ clear_other())
1104 	  terminateOtherLeg();
1105 	}
1106 
1107 	processed = onOtherReply(reply);
1108       }
1109 
1110       break;
1111 
1112     default:
1113       DBG("reply from callee: %u %s\n",reply.code,reply.reason.c_str());
1114       break;
1115     }
1116   }
1117 
1118   if (!processed)
1119     AmB2BSession::onB2BEvent(ev);
1120 }
1121 
relayEvent(AmEvent * ev)1122 int AmB2BCallerSession::relayEvent(AmEvent* ev)
1123 {
1124   if(getOtherId().empty() && !getStopped()){
1125 
1126     bool create_callee = false;
1127     B2BSipEvent* sip_ev = dynamic_cast<B2BSipEvent*>(ev);
1128     if (sip_ev && sip_ev->forward)
1129       create_callee = true;
1130     else
1131       create_callee = dynamic_cast<B2BConnectEvent*>(ev) != NULL;
1132 
1133     if (create_callee) {
1134       createCalleeSession();
1135       if (getOtherId().length()) {
1136 	MONITORING_LOG(getLocalTag().c_str(), "b2b_leg", getOtherId().c_str());
1137       }
1138     }
1139 
1140   }
1141 
1142   return AmB2BSession::relayEvent(ev);
1143 }
1144 
onInvite(const AmSipRequest & req)1145 void AmB2BCallerSession::onInvite(const AmSipRequest& req)
1146 {
1147   invite_req = req;
1148   est_invite_cseq = req.cseq;
1149 
1150   AmB2BSession::onInvite(req);
1151 }
1152 
onInvite2xx(const AmSipReply & reply)1153 void AmB2BCallerSession::onInvite2xx(const AmSipReply& reply)
1154 {
1155   invite_req.cseq = reply.cseq;
1156   est_invite_cseq = reply.cseq;
1157 
1158   AmB2BSession::onInvite2xx(reply);
1159 }
1160 
onCancel(const AmSipRequest & req)1161 void AmB2BCallerSession::onCancel(const AmSipRequest& req)
1162 {
1163   terminateOtherLeg();
1164   terminateLeg();
1165 }
1166 
onSystemEvent(AmSystemEvent * ev)1167 void AmB2BCallerSession::onSystemEvent(AmSystemEvent* ev) {
1168   if (ev->sys_event == AmSystemEvent::ServerShutdown) {
1169     terminateOtherLeg();
1170   }
1171 
1172   AmB2BSession::onSystemEvent(ev);
1173 }
1174 
onRemoteDisappeared(const AmSipReply & reply)1175 void AmB2BCallerSession::onRemoteDisappeared(const AmSipReply& reply) {
1176   DBG("remote unreachable, ending B2BUA call\n");
1177   clearRtpReceiverRelay();
1178 
1179   AmB2BSession::onRemoteDisappeared(reply);
1180 }
1181 
onBye(const AmSipRequest & req)1182 void AmB2BCallerSession::onBye(const AmSipRequest& req)
1183 {
1184   clearRtpReceiverRelay();
1185   AmB2BSession::onBye(req);
1186 }
1187 
connectCallee(const string & remote_party,const string & remote_uri,bool relayed_invite)1188 void AmB2BCallerSession::connectCallee(const string& remote_party,
1189 				       const string& remote_uri,
1190 				       bool relayed_invite)
1191 {
1192   if(callee_status != None)
1193     terminateOtherLeg();
1194 
1195   clear_other();
1196 
1197   if (relayed_invite) {
1198     // relayed INVITE - we need to add the original INVITE to
1199     // list of received (relayed) requests
1200     recvd_req.insert(std::make_pair(invite_req.cseq,invite_req));
1201 
1202     // in SIP relay mode from the beginning
1203     sip_relay_only = true;
1204   }
1205 
1206   B2BConnectEvent* ev = new B2BConnectEvent(remote_party,remote_uri);
1207 
1208   ev->body         = invite_req.body;
1209   ev->hdrs         = invite_req.hdrs;
1210   ev->relayed_invite = relayed_invite;
1211   ev->r_cseq       = invite_req.cseq;
1212 
1213   DBG("relaying B2B connect event to %s\n", remote_uri.c_str());
1214   relayEvent(ev);
1215   callee_status = NoReply;
1216 }
1217 
reinviteCaller(const AmSipReply & callee_reply)1218 int AmB2BCallerSession::reinviteCaller(const AmSipReply& callee_reply)
1219 {
1220   return dlg->sendRequest(SIP_METH_INVITE,
1221 			 &callee_reply.body,
1222 			 "" /* hdrs */, SIP_FLAGS_VERBATIM);
1223 }
1224 
createCalleeSession()1225 void AmB2BCallerSession::createCalleeSession() {
1226   AmB2BCalleeSession* callee_session = newCalleeSession();
1227   if (NULL == callee_session)
1228     return;
1229 
1230   AmSipDialog* callee_dlg = callee_session->dlg;
1231 
1232   setOtherId(AmSession::getNewId());
1233 
1234   callee_dlg->setLocalTag(getOtherId());
1235   if (callee_dlg->getCallid().empty())
1236     callee_dlg->setCallid(AmSession::getNewId());
1237 
1238   callee_dlg->setLocalParty(dlg->getRemoteParty());
1239   callee_dlg->setRemoteParty(dlg->getLocalParty());
1240   callee_dlg->setRemoteUri(dlg->getLocalUri());
1241 
1242   if (AmConfig::LogSessions) {
1243     INFO("Starting B2B callee session %s\n",
1244 	 callee_session->getLocalTag().c_str());
1245   }
1246 
1247   MONITORING_LOG4(getOtherId().c_str(),
1248 		  "dir",  "out",
1249 		  "from", callee_dlg->getLocalParty().c_str(),
1250 		  "to",   callee_dlg->getRemoteParty().c_str(),
1251 		  "ruri", callee_dlg->getRemoteUri().c_str());
1252 
1253   try {
1254     initializeRTPRelay(callee_session);
1255   } catch (...) {
1256     delete callee_session;
1257     throw;
1258   }
1259 
1260   AmSessionContainer* sess_cont = AmSessionContainer::instance();
1261   sess_cont->addSession(getOtherId(),callee_session);
1262 
1263   callee_session->start();
1264 }
1265 
newCalleeSession()1266 AmB2BCalleeSession* AmB2BCallerSession::newCalleeSession()
1267 {
1268   return new AmB2BCalleeSession(this);
1269 }
1270 
setMediaSession(AmB2BMedia * new_session)1271 void AmB2BSession::setMediaSession(AmB2BMedia *new_session)
1272 {
1273   // FIXME: ignore old media_session? can it be already set here?
1274   if (media_session) ERROR("BUG: non-empty media session overwritten\n");
1275   media_session = new_session;
1276   if (media_session)
1277     media_session->addReference(); // new reference for me
1278 }
1279 
initializeRTPRelay(AmB2BCalleeSession * callee_session)1280 void AmB2BCallerSession::initializeRTPRelay(AmB2BCalleeSession* callee_session) {
1281   if (!callee_session) return;
1282 
1283   callee_session->setRtpRelayMode(rtp_relay_mode);
1284   callee_session->setEnableDtmfTranscoding(enable_dtmf_transcoding);
1285   callee_session->setEnableDtmfRtpFiltering(enable_dtmf_rtp_filtering);
1286   callee_session->setEnableDtmfRtpDetection(enable_dtmf_rtp_detection);
1287   callee_session->setLowFiPLs(lowfi_payloads);
1288 
1289   if ((rtp_relay_mode == RTP_Relay) || (rtp_relay_mode == RTP_Transcoding)) {
1290     setMediaSession(new AmB2BMedia(this, callee_session)); // we need to add our reference
1291     callee_session->setMediaSession(getMediaSession());
1292   }
1293 }
1294 
AmB2BCalleeSession(const string & other_local_tag)1295 AmB2BCalleeSession::AmB2BCalleeSession(const string& other_local_tag)
1296   : AmB2BSession(other_local_tag)
1297 {
1298   a_leg = false;
1299 }
1300 
AmB2BCalleeSession(const AmB2BCallerSession * caller)1301 AmB2BCalleeSession::AmB2BCalleeSession(const AmB2BCallerSession* caller)
1302   : AmB2BSession(caller->getLocalTag())
1303 {
1304   a_leg = false;
1305   rtp_relay_mode = caller->getRtpRelayMode();
1306   rtp_relay_force_symmetric_rtp = caller->getRtpRelayForceSymmetricRtp();
1307 }
1308 
~AmB2BCalleeSession()1309 AmB2BCalleeSession::~AmB2BCalleeSession() {
1310 }
1311 
onB2BEvent(B2BEvent * ev)1312 void AmB2BCalleeSession::onB2BEvent(B2BEvent* ev)
1313 {
1314   if(ev->event_id == B2BConnectLeg){
1315     B2BConnectEvent* co_ev = dynamic_cast<B2BConnectEvent*>(ev);
1316     if (!co_ev)
1317       return;
1318 
1319     MONITORING_LOG3(getLocalTag().c_str(),
1320 		    "b2b_leg", getOtherId().c_str(),
1321 		    "to", co_ev->remote_party.c_str(),
1322 		    "ruri", co_ev->remote_uri.c_str());
1323 
1324 
1325     dlg->setRemoteParty(co_ev->remote_party);
1326     dlg->setRemoteUri(co_ev->remote_uri);
1327 
1328     if (co_ev->relayed_invite) {
1329       AmSipRequest fake_req;
1330       fake_req.method = SIP_METH_INVITE;
1331       fake_req.cseq = co_ev->r_cseq;
1332       relayed_req[dlg->cseq] = fake_req;
1333     }
1334 
1335     AmMimeBody body(co_ev->body);
1336     try {
1337       updateLocalBody(body);
1338     } catch (const string& s) {
1339       relayError(SIP_METH_INVITE, co_ev->r_cseq, co_ev->relayed_invite, 500,
1340           SIP_REPLY_SERVER_INTERNAL_ERROR);
1341       throw;
1342     }
1343 
1344     int res = dlg->sendRequest(SIP_METH_INVITE, &body,
1345 			co_ev->hdrs, SIP_FLAGS_VERBATIM);
1346     if (res < 0) {
1347       DBG("sending INVITE failed, relaying back error reply\n");
1348       relayError(SIP_METH_INVITE, co_ev->r_cseq, co_ev->relayed_invite, res);
1349 
1350       if (co_ev->relayed_invite)
1351 	relayed_req.erase(dlg->cseq);
1352 
1353       setStopped();
1354       return;
1355     }
1356 
1357     saveSessionDescription(co_ev->body);
1358 
1359     // save CSeq of establising INVITE
1360     est_invite_cseq = dlg->cseq - 1;
1361     est_invite_other_cseq = co_ev->r_cseq;
1362 
1363     return;
1364   }
1365 
1366   AmB2BSession::onB2BEvent(ev);
1367 }
1368 
1369 /** EMACS **
1370  * Local variables:
1371  * mode: c++
1372  * c-basic-offset: 2
1373  * End:
1374  */
1375