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