1 #include "AmBasicSipDialog.h"
2 
3 #include "AmConfig.h"
4 #include "AmSipHeaders.h"
5 #include "SipCtrlInterface.h"
6 #include "AmSession.h"
7 
8 #include "sip/parse_route.h"
9 #include "sip/parse_uri.h"
10 #include "sip/parse_next_hop.h"
11 #include "sip/msg_logger.h"
12 #include "sip/sip_parser.h"
13 
14 const char* AmBasicSipDialog::status2str[AmBasicSipDialog::__max_Status] = {
15   "Disconnected",
16   "Trying",
17   "Proceeding",
18   "Cancelling",
19   "Early",
20   "Connected",
21   "Disconnecting"
22 };
23 
test01()24 AmBasicSipDialog::AmBasicSipDialog(AmBasicSipEventHandler* h)
25   : status(Disconnected),
26     next_hop(AmConfig::NextHop),next_hop_1st_req(AmConfig::NextHop1stReq),patch_ruri_next_hop(false),
27     next_hop_fixed(false),
28     outbound_interface(-1),
29     usages(0),
30     hdl(h),
31     logger(0),
32     outbound_proxy(AmConfig::OutboundProxy),
33     force_outbound_proxy(AmConfig::ForceOutboundProxy),
34     nat_handling(AmConfig::SipNATHandling),
35     cseq(10),
36     r_cseq_i(false)
37 {
38   //assert(h);
39 }
40 
41 AmBasicSipDialog::~AmBasicSipDialog()
42 {
43   termUasTrans();
44   termUacTrans();
45   if (logger) dec_ref(logger);
46   dump();
47 }
48 
49 AmSipRequest* AmBasicSipDialog::getUACTrans(unsigned int t_cseq)
50 {
51   TransMap::iterator it = uac_trans.find(t_cseq);
52   if(it == uac_trans.end())
53     return NULL;
54 
55   return &(it->second);
56 }
57 
58 AmSipRequest* AmBasicSipDialog::getUASTrans(unsigned int t_cseq)
59 {
60   TransMap::iterator it = uas_trans.find(t_cseq);
61   if(it == uas_trans.end())
62     return NULL;
63 
64   return &(it->second);
65 }
66 
67 string AmBasicSipDialog::getUACTransMethod(unsigned int t_cseq)
68 {
69   AmSipRequest* req = getUACTrans(t_cseq);
70   if(req != NULL)
71     return req->method;
72 
73   return string();
74 }
75 
76 bool AmBasicSipDialog::getUACTransPending()
77 {
78   return !uac_trans.empty();
79 }
80 
81 void AmBasicSipDialog::setStatus(Status new_status)
82 {
83   DBG("setting SIP dialog status: %s->%s\n",
84       getStatusStr(), getStatusStr(new_status));
85 
86   status = new_status;
87 }
88 
89 const char* AmBasicSipDialog::getStatusStr(AmBasicSipDialog::Status st)
90 {
91   if((st < 0) || (st >= __max_Status))
92     return "Invalid";
93   else
94     return status2str[st];
95 }
96 
97 const char* AmBasicSipDialog::getStatusStr()
98 {
99   return getStatusStr(status);
100 }
101 
102 string AmBasicSipDialog::getContactHdr() {
103   AmUriParser tmp_contact = contact;
104   if(tmp_contact.uri_host.empty()) {
105     int oif = getOutboundIf();
106     assert(oif >= 0);
107     assert(oif < (int)AmConfig::SIP_Ifs.size());
108     tmp_contact.uri_host = AmConfig::SIP_Ifs[oif].getIP();
109     tmp_contact.uri_port = int2str(AmConfig::SIP_Ifs[oif].LocalPort);
110   }
111 
112   if(tmp_contact.uri_user.empty() && !ext_local_tag.empty()) {
113     tmp_contact.uri_user = local_tag;
114   }
115 
116   string contact_str = tmp_contact.print();
117 
118   DBG("[%s] resulting Contact header: %s",
119     local_tag.c_str(),
120     contact_str.c_str());
121 
122   return SIP_HDR_COLSP(SIP_HDR_CONTACT) + contact_str += CRLF;
123 }
124 
125 
126 string AmBasicSipDialog::getContactUri()
127 {
128   string contact_uri = "sip:";
129 
130   if(!ext_local_tag.empty()) {
131     contact_uri += local_tag + "@";
132   }
133 
134   int oif = getOutboundIf();
135   assert(oif >= 0);
136   assert(oif < (int)AmConfig::SIP_Ifs.size());
137 
138   contact_uri += AmConfig::SIP_Ifs[oif].getIP();
139   contact_uri += ":" + int2str(AmConfig::SIP_Ifs[oif].LocalPort);
140 
141   if(!contact_params.empty()) {
142     contact_uri += ";" + contact_params;
143   }
144 
145   return contact_uri;
146 }
147 
148 string AmBasicSipDialog::getRoute()
149 {
150   string res;
151 
152   if(!outbound_proxy.empty() && (force_outbound_proxy || remote_tag.empty())){
153     res += "<" + outbound_proxy + ";lr>";
154 
155     if(!route.empty()) {
156       res += ",";
157     }
158   }
159 
160   res += route;
161 
162   if(!res.empty()) {
163     res = SIP_HDR_COLSP(SIP_HDR_ROUTE) + res + CRLF;
164   }
165 
166   return res;
167 }
168 
169 void AmBasicSipDialog::setOutboundInterface(int interface_id) {
170   DBG("setting outbound interface to %i\n",  interface_id);
171   outbound_interface = interface_id;
172 }
173 
174 /**
175  * Computes, set and return the outbound interface
176  * based on remote_uri, next_hop_ip, outbound_proxy, route.
177  */
178 int AmBasicSipDialog::getOutboundIf()
179 {
180   if (outbound_interface >= 0)
181     return outbound_interface;
182 
183   if(AmConfig::SIP_Ifs.size() == 1){
184     return (outbound_interface = 0);
185   }
186 
187   // Destination priority:
188   // 1. next_hop
189   // 2. outbound_proxy (if 1st req or force_outbound_proxy)
190   // 3. first route
191   // 4. remote URI
192 
193   string dest_uri;
194   string dest_ip;
195   string local_ip;
196   multimap<string,unsigned short>::iterator if_it;
197 
198   list<sip_destination> ip_list;
199   if(!next_hop.empty() &&
200      !parse_next_hop(stl2cstr(next_hop),ip_list) &&
201      !ip_list.empty()) {
202 
203     dest_ip = c2stlstr(ip_list.front().host);
204   }
205   else if(!outbound_proxy.empty() &&
206 	  (remote_tag.empty() || force_outbound_proxy)) {
207     dest_uri = outbound_proxy;
208   }
209   else if(!route.empty()){
210     // parse first route
211     sip_header fr;
212     fr.value = stl2cstr(route);
213     sip_uri* route_uri = get_first_route_uri(&fr);
214     if(!route_uri){
215       ERROR("Could not parse route (local_tag='%s';route='%s')",
216 	    local_tag.c_str(),route.c_str());
217       goto error;
218     }
219 
220     dest_ip = c2stlstr(route_uri->host);
221   }
222   else {
223     dest_uri = remote_uri;
224   }
225 
226   if(dest_uri.empty() && dest_ip.empty()) {
227     ERROR("No destination found (local_tag='%s')",local_tag.c_str());
228     goto error;
229   }
230 
231   if(!dest_uri.empty()){
232     sip_uri d_uri;
233     if(parse_uri(&d_uri,dest_uri.c_str(),dest_uri.length()) < 0){
234       ERROR("Could not parse destination URI (local_tag='%s';dest_uri='%s')",
235 	    local_tag.c_str(),dest_uri.c_str());
236       goto error;
237     }
238 
239     dest_ip = c2stlstr(d_uri.host);
240   }
241 
242   if(get_local_addr_for_dest(dest_ip,local_ip) < 0){
243     ERROR("No local address for dest '%s' (local_tag='%s')",dest_ip.c_str(),local_tag.c_str());
244     goto error;
245   }
246 
247   if_it = AmConfig::LocalSIPIP2If.find(local_ip);
248   if(if_it == AmConfig::LocalSIPIP2If.end()){
249     ERROR("Could not find a local interface for resolved local IP (local_tag='%s';local_ip='%s')",
250 	  local_tag.c_str(), local_ip.c_str());
251     goto error;
252   }
253 
254   setOutboundInterface(if_it->second);
255   return if_it->second;
256 
257  error:
258   WARN("Error while computing outbound interface: default interface will be used instead.");
259   setOutboundInterface(0);
260   return 0;
261 }
262 
263 void AmBasicSipDialog::resetOutboundIf()
264 {
265   setOutboundInterface(-1);
266 }
267 
268 /**
269  * Update dialog status from UAC Request that we send.
270  */
271 void AmBasicSipDialog::initFromLocalRequest(const AmSipRequest& req)
272 {
273   setRemoteUri(req.r_uri);
274 
275   user         = req.user;
276   domain       = req.domain;
277 
278   setCallid(      req.callid   );
279   setLocalTag(    req.from_tag );
280   setLocalUri(    req.from_uri );
281   setRemoteParty( req.to       );
282   setLocalParty(  req.from     );
283 }
284 
285 bool AmBasicSipDialog::onRxReqSanity(const AmSipRequest& req)
286 {
287   // Sanity checks
288   if(!remote_tag.empty() && !req.from_tag.empty() &&
289      (req.from_tag != remote_tag)){
290     DBG("remote_tag = '%s'; req.from_tag = '%s'\n",
291 	remote_tag.c_str(), req.from_tag.c_str());
292     reply_error(req, 481, SIP_REPLY_NOT_EXIST);
293     return false;
294   }
295 
296   if (r_cseq_i && req.cseq <= r_cseq){
297 
298     if (req.method == SIP_METH_NOTIFY) {
299       if (!AmConfig::IgnoreNotifyLowerCSeq) {
300 	// clever trick to not break subscription dialog usage
301 	// for implementations which follow 3265 instead of 5057
302 	string hdrs = SIP_HDR_COLSP(SIP_HDR_RETRY_AFTER)  "0"  CRLF;
303 
304 	INFO("remote cseq lower than previous ones - refusing request\n");
305 	// see 12.2.2
306 	reply_error(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR, hdrs);
307 	return false;
308       }
309     }
310     else {
311       INFO("remote cseq lower than previous ones - refusing request\n");
312       // see 12.2.2
313       reply_error(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR);
314       return false;
315     }
316   }
317 
318   r_cseq = req.cseq;
319   r_cseq_i = true;
320 
321   return true;
322 }
323 
324 void AmBasicSipDialog::onRxRequest(const AmSipRequest& req)
325 {
326   DBG("AmBasicSipDialog::onRxRequest(req = %s)\n", req.method.c_str());
327 
328   if(logger && (req.method != SIP_METH_ACK)) {
329     // log only non-initial received requests, the initial one is already logged
330     // or will be logged at application level (problem with SBCSimpleRelay)
331     if (!callid.empty()) req.log(logger);
332   }
333 
334   if(!onRxReqSanity(req))
335     return;
336 
337   uas_trans[req.cseq] = req;
338 
339   // target refresh requests
340   if (req.from_uri.length() &&
341       (remote_uri.empty() ||
342        (req.method == SIP_METH_INVITE ||
343 	req.method == SIP_METH_UPDATE ||
344 	req.method == SIP_METH_SUBSCRIBE ||
345 	req.method == SIP_METH_NOTIFY))) {
346 
347     // refresh the target
348     if (remote_uri != req.from_uri) {
349       setRemoteUri(req.from_uri);
350       if(nat_handling && req.first_hop) {
351 	string nh = req.remote_ip + ":"
352 	  + int2str(req.remote_port)
353 	  + "/" + req.trsp;
354 	setNextHop(nh);
355 	setNextHop1stReq(false);
356       }
357     }
358 
359     string ua = getHeader(req.hdrs,"User-Agent");
360     setRemoteUA(ua);
361   }
362 
363   // Dlg not yet initialized?
364   if(callid.empty()){
365 
366     user         = req.user;
367     domain       = req.domain;
368 
369     setCallid(      req.callid   );
370     setRemoteTag(   req.from_tag );
371     setLocalUri(    req.r_uri    );
372     setRemoteParty( req.from     );
373     setLocalParty(  req.to       );
374     setRouteSet(    req.route    );
375     set1stBranch(   req.via_branch );
376     setOutboundInterface( req.local_if );
377   }
378 
379   if(onRxReqStatus(req) && hdl)
380     hdl->onSipRequest(req);
381 }
382 
383 bool AmBasicSipDialog::onRxReplyStatus(const AmSipReply& reply)
384 {
385   /**
386    * Error code list from RFC 5057:
387    * those error codes terminate the dialog
388    *
389    * Note: 408, 480 should only terminate
390    *       the usage according to RFC 5057.
391    */
392   switch(reply.code){
393   case 404:
394   case 408:
395   case 410:
396   case 416:
397   case 480:
398   case 482:
399   case 483:
400   case 484:
401   case 485:
402   case 502:
403   case 604:
404     if(hdl) hdl->onRemoteDisappeared(reply);
405     break;
406   }
407 
408   return true;
409 }
410 
411 void AmBasicSipDialog::termUasTrans()
412 {
413   while(!uas_trans.empty()) {
414 
415     TransMap::iterator it = uas_trans.begin();
416     int req_cseq = it->first;
417     const AmSipRequest& req = it->second;
418     DBG("terminating UAS transaction (%u %s)",req.cseq,req.cseq_method.c_str());
419 
420     reply(req,481,SIP_REPLY_NOT_EXIST);
421 
422     it = uas_trans.find(req_cseq);
423     if(it != uas_trans.end())
424       uas_trans.erase(it);
425   }
426 }
427 
428 void AmBasicSipDialog::termUacTrans()
429 {
430   while(!uac_trans.empty()) {
431     TransMap::iterator it = uac_trans.begin();
432     trans_ticket& tt = it->second.tt;
433 
434     tt.lock_bucket();
435     tt.remove_trans();
436     tt.unlock_bucket();
437 
438     uac_trans.erase(it);
439   }
440 }
441 
442 void AmBasicSipDialog::dropTransactions() {
443   termUacTrans();
444   uas_trans.clear();
445 }
446 
447 bool AmBasicSipDialog::onRxReplySanity(const AmSipReply& reply)
448 {
449   if(ext_local_tag.empty()) {
450     if(reply.from_tag != local_tag) {
451       ERROR("received reply with wrong From-tag ('%s' vs. '%s')\n",
452 	    reply.from_tag.c_str(), local_tag.c_str());
453       throw string("reply has wrong from-tag");
454       //return;
455     }
456   }
457   else if(reply.from_tag != ext_local_tag) {
458     ERROR("received reply with wrong From-tag ('%s' vs. '%s')\n",
459 	  reply.from_tag.c_str(), ext_local_tag.c_str());
460     throw string("reply has wrong from-tag");
461     //return;
462   }
463 
464   return true;
465 }
466 
467 void AmBasicSipDialog::onRxReply(const AmSipReply& reply)
468 {
469   if(!onRxReplySanity(reply)) {
470     DBG("onRxReply (rep = %u %s): sanity check failed!\n",
471 	reply.code, reply.reason.c_str());
472     return;
473   }
474 
475   TransMap::iterator t_it = uac_trans.find(reply.cseq);
476   if(t_it == uac_trans.end()){
477     ERROR("could not find any transaction matching reply: %s\n",
478         ((AmSipReply)reply).print().c_str());
479     return;
480   }
481 
482   DBG("onRxReply(rep = %u %s): transaction found!\n",
483       reply.code, reply.reason.c_str());
484 
485   updateDialogTarget(reply);
486 
487   Status saved_status = status;
488   AmSipRequest orig_req(t_it->second);
489 
490   if(onRxReplyStatus(reply) && hdl) {
491     hdl->onSipReply(orig_req,reply,saved_status);
492   }
493 
494   if((reply.code >= 200) && // final reply
495      // but not for 2xx INV reply (wait for 200 ACK)
496      ((reply.cseq_method != SIP_METH_INVITE) ||
497       (reply.code >= 300))) {
498 
499     uac_trans.erase(reply.cseq);
500     if (hdl) hdl->onTransFinished();
501   }
502 }
503 
504 void AmBasicSipDialog::updateDialogTarget(const AmSipReply& reply)
505 {
506   if( (reply.code > 100) && (reply.code < 300) &&
507       !reply.to_uri.empty() &&
508       !reply.to_tag.empty() &&
509       (remote_uri.empty() ||
510        (reply.cseq_method.length()==6 &&
511 	((reply.cseq_method == SIP_METH_INVITE) ||
512 	 (reply.cseq_method == SIP_METH_UPDATE) ||
513 	 (reply.cseq_method == SIP_METH_NOTIFY))) ||
514        (reply.cseq_method == SIP_METH_SUBSCRIBE)) ) {
515 
516     setRemoteUri(reply.to_uri);
517     if(!getNextHop().empty()) {
518       string nh = reply.remote_ip
519 	+ ":" + int2str(reply.remote_port)
520 	+ "/" + reply.trsp;
521       setNextHop(nh);
522     }
523 
524     string ua = getHeader(reply.hdrs,"Server");
525     setRemoteUA(ua);
526   }
527 }
528 
529 void AmBasicSipDialog::setRemoteTag(const string& new_rt)
530 {
531   if(new_rt != remote_tag){
532     remote_tag = new_rt;
533   }
534 }
535 
536 int AmBasicSipDialog::onTxRequest(AmSipRequest& req, int& flags)
537 {
538   if(hdl) hdl->onSendRequest(req,flags);
539 
540   return 0;
541 }
542 
543 int AmBasicSipDialog::onTxReply(const AmSipRequest& req,
544 				AmSipReply& reply, int& flags)
545 {
546   if(hdl) hdl->onSendReply(req,reply,flags);
547 
548   return 0;
549 }
550 
551 void AmBasicSipDialog::onReplyTxed(const AmSipRequest& req,
552 				   const AmSipReply& reply)
553 {
554   if(hdl) hdl->onReplySent(req, reply);
555 
556   /**
557    * Error code list from RFC 5057:
558    * those error codes terminate the dialog
559    *
560    * Note: 408, 480 should only terminate
561    *       the usage according to RFC 5057.
562    */
563   switch(reply.code){
564   case 404:
565   case 408:
566   case 410:
567   case 416:
568   case 480:
569   case 482:
570   case 483:
571   case 484:
572   case 485:
573   case 502:
574   case 604:
575     if(hdl) hdl->onLocalTerminate(reply);
576     break;
577   }
578 
579   if ((reply.code >= 200) &&
580       (reply.cseq_method != SIP_METH_CANCEL)) {
581 
582     uas_trans.erase(reply.cseq);
583     if (hdl) hdl->onTransFinished();
584   }
585 }
586 
587 void AmBasicSipDialog::onRequestTxed(const AmSipRequest& req)
588 {
589   if(hdl) hdl->onRequestSent(req);
590 
591   if(req.method != SIP_METH_ACK) {
592     uac_trans[req.cseq] = req;
593     cseq++;
594   }
595   else {
596     uac_trans.erase(req.cseq);
597     if (hdl) hdl->onTransFinished();
598   }
599 }
600 
601 int AmBasicSipDialog::reply(const AmSipRequest& req,
602 			    unsigned int  code,
603 			    const string& reason,
604 			    const AmMimeBody* body,
605 			    const string& hdrs,
606 			    int flags)
607 {
608   TransMap::const_iterator t_it = uas_trans.find(req.cseq);
609   if(t_it == uas_trans.end()){
610     ERROR("could not find any transaction matching request cseq\n");
611     ERROR("request cseq=%i; reply code=%i; callid=%s; local_tag=%s; "
612 	  "remote_tag=%s\n",
613 	  req.cseq,code,callid.c_str(),
614 	  local_tag.c_str(),remote_tag.c_str());
615     log_stacktrace(L_ERR);
616     return -1;
617   }
618   DBG("reply: transaction found!\n");
619 
620   AmSipReply reply;
621 
622   reply.code = code;
623   reply.reason = reason;
624   reply.tt = req.tt;
625   if((code > 100) && !(flags & SIP_FLAGS_NOTAG))
626     reply.to_tag = ext_local_tag.empty() ? local_tag : ext_local_tag;
627   reply.hdrs = hdrs;
628   reply.cseq = req.cseq;
629   reply.cseq_method = req.method;
630 
631   if(body != NULL)
632     reply.body = *body;
633 
634   if(onTxReply(req,reply,flags)){
635     DBG("onTxReply failed\n");
636     return -1;
637   }
638 
639   if (!(flags & SIP_FLAGS_VERBATIM)) {
640     // add Signature
641     if (AmConfig::Signature.length())
642       reply.hdrs += SIP_HDR_COLSP(SIP_HDR_SERVER) + AmConfig::Signature + CRLF;
643   }
644 
645   if ((code > 100 && code < 300) && !(flags & SIP_FLAGS_NOCONTACT)) {
646     /* if 300<=code<400, explicit contact setting should be done */
647     reply.contact = getContactHdr();
648   }
649 
650   int ret = SipCtrlInterface::send(reply,local_tag,logger);
651   if(ret){
652     ERROR("Could not send reply: code=%i; reason='%s'; method=%s;"
653 	  " call-id=%s; cseq=%i\n",
654 	  reply.code,reply.reason.c_str(),reply.cseq_method.c_str(),
655 	  callid.c_str(),reply.cseq);
656 
657     return ret;
658   }
659   else {
660     onReplyTxed(req,reply);
661   }
662 
663   return ret;
664 }
665 
666 
667 /* static */
668 int AmBasicSipDialog::reply_error(const AmSipRequest& req, unsigned int code,
669 				  const string& reason, const string& hdrs,
670 				  msg_logger* logger)
671 {
672   AmSipReply reply;
673 
674   reply.code = code;
675   reply.reason = reason;
676   reply.tt = req.tt;
677   reply.hdrs = hdrs;
678   reply.to_tag = AmSession::getNewId();
679 
680   if (AmConfig::Signature.length())
681     reply.hdrs += SIP_HDR_COLSP(SIP_HDR_SERVER) + AmConfig::Signature + CRLF;
682 
683   // add transcoder statistics into reply headers
684   //addTranscoderStats(reply.hdrs);
685 
686   int ret = SipCtrlInterface::send(reply,string(""),logger);
687   if(ret){
688     ERROR("Could not send reply: code=%i; reason='%s';"
689 	  " method=%s; call-id=%s; cseq=%i\n",
690 	  reply.code,reply.reason.c_str(),
691 	  req.method.c_str(),req.callid.c_str(),req.cseq);
692   }
693 
694   return ret;
695 }
696 
697 int AmBasicSipDialog::sendRequest(const string& method,
698 				  const AmMimeBody* body,
699 				  const string& hdrs,
700 				  int flags,
701 				  int max_forwards)
702 {
703   AmSipRequest req;
704 
705   req.method = method;
706   req.r_uri = remote_uri;
707 
708   req.from = SIP_HDR_COLSP(SIP_HDR_FROM) + local_party;
709   if(!ext_local_tag.empty())
710     req.from += ";tag=" + ext_local_tag;
711   else if(!local_tag.empty())
712     req.from += ";tag=" + local_tag;
713 
714   req.to = SIP_HDR_COLSP(SIP_HDR_TO) + remote_party;
715   if(!remote_tag.empty())
716     req.to += ";tag=" + remote_tag;
717 
718   req.cseq = cseq;
719   req.callid = callid;
720 
721   req.hdrs = hdrs;
722 
723   req.route = getRoute();
724 
725   if(body != NULL) {
726     req.body = *body;
727   }
728 
729   if(onTxRequest(req,flags) < 0)
730     return -1;
731 
732   if (!(flags & SIP_FLAGS_NOCONTACT)) {
733     req.contact = getContactHdr();
734   }
735 
736   if (!(flags & SIP_FLAGS_VERBATIM)) {
737     // add Signature
738     if (AmConfig::Signature.length())
739       req.hdrs += SIP_HDR_COLSP(SIP_HDR_USER_AGENT) + AmConfig::Signature + CRLF;
740   }
741 
742   int send_flags = 0;
743   if(patch_ruri_next_hop && remote_tag.empty()) {
744     send_flags |= TR_FLAG_NEXT_HOP_RURI;
745   }
746 
747   if((flags & SIP_FLAGS_NOBL) ||
748      !remote_tag.empty()) {
749     send_flags |= TR_FLAG_DISABLE_BL;
750   }
751 
752   if (req.max_forwards > (int)AmConfig::MaxForwards) {
753     req.max_forwards = AmConfig::MaxForwards;
754   } else {
755     req.max_forwards = max_forwards;
756   };
757 
758   int res = SipCtrlInterface::send(req, local_tag,
759 				   remote_tag.empty() || !next_hop_1st_req ?
760 				   next_hop : "",
761 				   outbound_interface,
762 				   send_flags,logger);
763   if(res) {
764     ERROR("Could not send request: method=%s; call-id=%s; cseq=%i\n",
765 	  req.method.c_str(),req.callid.c_str(),req.cseq);
766     return res;
767   }
768 
769   onRequestTxed(req);
770   return 0;
771 }
772 
773 void AmBasicSipDialog::dump()
774 {
775   DBG("callid = %s\n",callid.c_str());
776   DBG("local_tag = %s\n",local_tag.c_str());
777   DBG("uac_trans.size() = %zu\n",uac_trans.size());
778   if(uac_trans.size()){
779     for(TransMap::iterator it = uac_trans.begin();
780 	it != uac_trans.end(); it++){
781 
782       DBG("    cseq = %i; method = %s\n",it->first,it->second.method.c_str());
783     }
784   }
785   DBG("uas_trans.size() = %zu\n",uas_trans.size());
786   if(uas_trans.size()){
787     for(TransMap::iterator it = uas_trans.begin();
788 	it != uas_trans.end(); it++){
789 
790       DBG("    cseq = %i; method = %s\n",it->first,it->second.method.c_str());
791     }
792   }
793 }
794 
795 void AmBasicSipDialog::setMsgLogger(msg_logger* logger)
796 {
797   if(this->logger) {
798     dec_ref(this->logger);
799   }
800 
801   if(logger){
802     inc_ref(logger);
803   }
804 
805   this->logger = logger;
806 }
807