Browse code

split AmSipDialog and AmBasicSipDialog (WIP)

Raphael Coeffic authored on 28/11/2012 14:58:28
Showing 24 changed files
... ...
@@ -191,9 +191,9 @@ void AnnounceTransferDialog::onSipRequest(const AmSipRequest& req)
191 191
 }
192 192
 
193 193
 void AnnounceTransferDialog::onSipReply(const AmSipReply& rep, AmSipDialog::Status old_dlg_status) {
194
-  AmSipTransaction* trans = dlg.getUACTrans(rep.cseq);
194
+  AmSipRequest* req = dlg.getUACTrans(rep.cseq);
195 195
   if ((status==Transfering ||status==Hangup)  && 
196
-      trans && trans->method == "REFER") {
196
+      req && req->method == "REFER") {
197 197
     if (rep.code >= 300) {
198 198
       DBG("refer not accepted, stop session.\n");
199 199
       dlg.bye();
... ...
@@ -4,7 +4,7 @@ COREPATH = $(DSMPATH)/../../core
4 4
 
5 5
 include $(COREPATH)/../Makefile.defs
6 6
 
7
-exclude_dsm_modules ?= mod_mysql mod_aws mod_curl mod_xml
7
+exclude_dsm_modules ?= mod_mysql mod_aws mod_curl mod_xml mod_subscription
8 8
 
9 9
 ifneq ($(USE_MONITORING), yes)
10 10
 exclude_dsm_modules += mod_monitoring
... ...
@@ -56,7 +56,7 @@ def_IvrSipDialog_GETTER(IvrSipDialog_getuser,         user)
56 56
 def_IvrSipDialog_GETTER(IvrSipDialog_getdomain,       domain)
57 57
 def_IvrSipDialog_GETTER(IvrSipDialog_getlocal_uri,    local_uri)
58 58
 def_IvrSipDialog_GETTER(IvrSipDialog_getremote_uri,   remote_uri)
59
-def_IvrSipDialog_GETTER(IvrSipDialog_getcontact_uri,  contact_uri)
59
+//def_IvrSipDialog_GETTER(IvrSipDialog_getcontact_uri,  contact_uri)
60 60
 def_IvrSipDialog_GETTER(IvrSipDialog_getcallid,       callid)
61 61
 def_IvrSipDialog_GETTER(IvrSipDialog_getremote_tag,   remote_tag)
62 62
 def_IvrSipDialog_GETTER(IvrSipDialog_getlocal_tag,    local_tag)
... ...
@@ -102,7 +102,7 @@ static PyGetSetDef IvrSipDialog_getset[] = {
102 102
   {(char*)"domain",      (getter)IvrSipDialog_getdomain, NULL, (char*)"local domain", NULL},
103 103
   {(char*)"local_uri",   (getter)IvrSipDialog_getlocal_uri, NULL, (char*)"local uri", NULL},
104 104
   {(char*)"remote_uri",  (getter)IvrSipDialog_getremote_uri, (setter)IvrSipDialog_setremote_uri, (char*)"remote uri", NULL},
105
-  {(char*)"contact_uri", (getter)IvrSipDialog_getcontact_uri, NULL, (char*)"pre-calculated contact uri", NULL},
105
+  //{(char*)"contact_uri", (getter)IvrSipDialog_getcontact_uri, NULL, (char*)"pre-calculated contact uri", NULL},
106 106
   {(char*)"callid",      (getter)IvrSipDialog_getcallid, NULL, (char*)"call id", NULL},
107 107
   {(char*)"remote_tag",  (getter)IvrSipDialog_getremote_tag, NULL, (char*)"remote tag", NULL},
108 108
   {(char*)"local_tag",   (getter)IvrSipDialog_getlocal_tag, NULL, (char*)"local tag", NULL},
... ...
@@ -148,13 +148,13 @@ void RtmpSession::process(AmEvent* ev)
148 148
       setStopped();
149 149
       return;
150 150
     case RtmpSessionEvent::Accept:
151
-      AmSipTransaction* inv_trans = dlg.getPendingUASInv();
152
-      if(!inv_trans){
151
+      AmSipRequest* inv_req = dlg.getUASPendingInv();
152
+      if(!inv_req){
153 153
 	//Error: no pending INVITE
154 154
 	sendCallState();
155 155
 	return;
156 156
       }
157
-      dlg.reply(*inv_trans,200,"OK");
157
+      dlg.reply(*inv_req,200,"OK");
158 158
       sendCallState();
159 159
       return;
160 160
     }
... ...
@@ -1898,9 +1898,10 @@ SBCCalleeSession::SBCCalleeSession(const AmB2BCallerSession* caller,
1898 1898
 {
1899 1899
   dlg.setRel100State(Am100rel::REL100_IGNORED);
1900 1900
 
1901
-  if (!call_profile.contact.empty()) {
1902
-    dlg.contact_uri = SIP_HDR_COLSP(SIP_HDR_CONTACT) + call_profile.contact + CRLF;
1903
-  }
1901
+  // TODO: fix this!!!
1902
+  // if (!call_profile.contact.empty()) {
1903
+  //   dlg.contact_uri = SIP_HDR_COLSP(SIP_HDR_CONTACT) + call_profile.contact + CRLF;
1904
+  // }
1904 1905
 }
1905 1906
 
1906 1907
 SBCCalleeSession::~SBCCalleeSession() {
... ...
@@ -213,13 +213,11 @@ void WebConferenceDialog::onEarlySessionStart() {
213 213
 void WebConferenceDialog::onSipReply(const AmSipReply& reply,
214 214
 				     AmSipDialog::Status old_dlg_status)
215 215
 {
216
-  //int status = dlg.getStatus();
217
-
218 216
   AmSession::onSipReply(reply,old_dlg_status);
219 217
 
220 218
   DBG("reply: %u %s, old_dlg_status = %s, status = %s\n",
221 219
       reply.code, reply.reason.c_str(),
222
-      dlgStatusStr(old_dlg_status),
220
+      AmBasicSipDialog::getStatusStr(old_dlg_status),
223 221
       dlg.getStatusStr());
224 222
 
225 223
   if ((old_dlg_status < AmSipDialog::Connected) && 
... ...
@@ -40,7 +40,10 @@ int  Am100rel::onRequestIn(const AmSipRequest& req)
40 40
               SIP_EXT_100REL))) {
41 41
           ERROR("'" SIP_EXT_100REL "' extension required, but not advertised"
42 42
             " by peer.\n");
43
-          if (hdl) hdl->onFailure(FAIL_REL100_421, &req, 0);
43
+	  AmBasicSipDialog::reply_error(req, 421, SIP_REPLY_EXTENSION_REQUIRED,
44
+					SIP_HDR_COLSP(SIP_HDR_REQUIRE) 
45
+					SIP_EXT_100REL CRLF);
46
+          if (hdl) hdl->onFailure();
44 47
           return 0; // has been replied
45 48
         }
46 49
         break; // 100rel required
... ...
@@ -48,7 +51,10 @@ int  Am100rel::onRequestIn(const AmSipRequest& req)
48 51
       case REL100_DISABLED:
49 52
         // TODO: shouldn't this be part of a more general check in SEMS?
50 53
         if (key_in_list(getHeader(req.hdrs,SIP_HDR_REQUIRE),SIP_EXT_100REL)) {
51
-          if (hdl) hdl->onFailure(FAIL_REL100_420, &req, 0);
54
+          AmBasicSipDialog::reply_error(req, 420, SIP_REPLY_BAD_EXTENSION,
55
+					SIP_HDR_COLSP(SIP_HDR_UNSUPPORTED) 
56
+					SIP_EXT_100REL CRLF);
57
+          if (hdl) hdl->onFailure();
52 58
           return 0; // has been replied
53 59
         }
54 60
         break;
... ...
@@ -102,10 +108,11 @@ int  Am100rel::onReplyIn(const AmSipReply& reply)
102 108
           !reply.rseq) {
103 109
         ERROR(SIP_EXT_100REL " not supported or no positive RSeq value in "
104 110
             "(reliable) 1xx.\n");
105
-        if (hdl) hdl->onFailure(FAIL_REL100_421, 0, &reply);
111
+	dlg->bye();
112
+        if (hdl) hdl->onFailure();
106 113
       } else {
107 114
         DBG(SIP_EXT_100REL " now active.\n");
108
-        if (hdl) hdl->onInvite1xxRel(reply);
115
+        if (hdl) ((AmSipDialogEventHandler*)hdl)->onInvite1xxRel(reply);
109 116
       }
110 117
       break;
111 118
 
... ...
@@ -122,9 +129,11 @@ int  Am100rel::onReplyIn(const AmSipReply& reply)
122 129
   } else if (reliable_1xx && reply.cseq_method==SIP_METH_PRACK) {
123 130
     if (300 <= reply.code) {
124 131
       // if PRACK fails, tear down session
125
-      if (hdl) hdl->onFailure(FAIL_REL100_421, 0, &reply);
132
+      dlg->bye();
133
+      if (hdl) hdl->onFailure();
126 134
     } else if (200 <= reply.code) {
127
-      if (hdl) hdl->onPrack2xx(reply);
135
+      if (hdl) 
136
+	((AmSipDialogEventHandler*)hdl)->onPrack2xx(reply);
128 137
     } else {
129 138
       WARN("received '%d' for " SIP_METH_PRACK " method.\n", reply.code);
130 139
     }
... ...
@@ -712,7 +712,7 @@ bool AmB2BSession::refresh(int flags) {
712 712
 int AmB2BSession::relaySip(const AmSipRequest& req)
713 713
 {
714 714
   if (req.method != "ACK") {
715
-    relayed_req[dlg.cseq] = AmSipTransaction(req.method,req.cseq,req.tt);
715
+    relayed_req[dlg.cseq] = req;
716 716
 
717 717
     const string* hdrs = &req.hdrs;
718 718
     string m_hdrs;
... ...
@@ -1230,8 +1230,10 @@ void AmB2BCalleeSession::onB2BEvent(B2BEvent* ev)
1230 1230
     dlg.remote_uri   = co_ev->remote_uri;
1231 1231
 
1232 1232
     if (co_ev->relayed_invite) {
1233
-      relayed_req[dlg.cseq] =
1234
-	AmSipTransaction(SIP_METH_INVITE, co_ev->r_cseq, trans_ticket());
1233
+      AmSipRequest fake_req;
1234
+      fake_req.method = SIP_METH_INVITE;
1235
+      fake_req.cseq = co_ev->r_cseq;
1236
+      relayed_req[dlg.cseq] = fake_req;
1235 1237
     }
1236 1238
 
1237 1239
     AmMimeBody r_body(co_ev->body);
1238 1240
new file mode 100644
... ...
@@ -0,0 +1,615 @@
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
+
12
+const char* AmBasicSipDialog::status2str[AmBasicSipDialog::__max_Status] = {
13
+  "Disconnected",
14
+  "Trying",
15
+  "Proceeding",
16
+  "Cancelling",
17
+  "Early",
18
+  "Connected",
19
+  "Disconnecting"
20
+};
21
+
22
+AmBasicSipDialog::AmBasicSipDialog(AmBasicSipEventHandler* h)
23
+  : status(Disconnected),
24
+    cseq(10),r_cseq_i(false),hdl(h),
25
+    outbound_proxy(AmConfig::OutboundProxy),
26
+    force_outbound_proxy(AmConfig::ForceOutboundProxy),
27
+    next_hop(AmConfig::NextHop),
28
+    next_hop_1st_req(AmConfig::NextHop1stReq),
29
+    outbound_interface(-1)
30
+{
31
+  assert(h);
32
+}
33
+
34
+AmBasicSipDialog::~AmBasicSipDialog()
35
+{
36
+  DBG("callid = %s\n",callid.c_str());
37
+  DBG("local_tag = %s\n",local_tag.c_str());
38
+  DBG("uac_trans.size() = %u\n",(unsigned int)uac_trans.size());
39
+  if(uac_trans.size()){
40
+    for(TransMap::iterator it = uac_trans.begin();
41
+	it != uac_trans.end(); it++){
42
+	    
43
+      DBG("    cseq = %i; method = %s\n",it->first,it->second.method.c_str());
44
+    }
45
+  }
46
+  DBG("uas_trans.size() = %u\n",(unsigned int)uas_trans.size());
47
+  if(uas_trans.size()){
48
+    for(TransMap::iterator it = uas_trans.begin();
49
+	it != uas_trans.end(); it++){
50
+	    
51
+      DBG("    cseq = %i; method = %s\n",it->first,it->second.method.c_str());
52
+    }
53
+  }
54
+}
55
+
56
+AmSipRequest* AmBasicSipDialog::getUACTrans(unsigned int t_cseq)
57
+{
58
+  TransMap::iterator it = uac_trans.find(t_cseq);
59
+  if(it == uac_trans.end())
60
+    return NULL;
61
+  
62
+  return &(it->second);
63
+}
64
+
65
+AmSipRequest* AmBasicSipDialog::getUASTrans(unsigned int t_cseq)
66
+{
67
+  TransMap::iterator it = uas_trans.find(t_cseq);
68
+  if(it == uas_trans.end())
69
+    return NULL;
70
+  
71
+  return &(it->second);
72
+}
73
+
74
+string AmBasicSipDialog::getUACTransMethod(unsigned int t_cseq)
75
+{
76
+  AmSipRequest* req = getUACTrans(t_cseq);
77
+  if(req != NULL)
78
+    return req->method;
79
+
80
+  return string();
81
+}
82
+
83
+bool AmBasicSipDialog::getUACTransPending()
84
+{
85
+  return !uac_trans.empty();
86
+}
87
+
88
+void AmBasicSipDialog::setStatus(Status new_status) 
89
+{
90
+  DBG("setting SIP dialog status: %s->%s\n",
91
+      getStatusStr(), getStatusStr(new_status));
92
+
93
+  status = new_status;
94
+}
95
+
96
+const char* AmBasicSipDialog::getStatusStr(AmBasicSipDialog::Status st)
97
+{
98
+  if((st < 0) || (st >= __max_Status))
99
+    return "Invalid";
100
+  else
101
+    return status2str[st];
102
+}
103
+
104
+const char* AmBasicSipDialog::getStatusStr()
105
+{
106
+  return getStatusStr(status);
107
+}
108
+
109
+string AmBasicSipDialog::getContactHdr()
110
+{
111
+  string contact_uri = SIP_HDR_COLSP(SIP_HDR_CONTACT) "<sip:";
112
+
113
+  if(!user.empty()) {
114
+    contact_uri += user + "@";
115
+  }
116
+    
117
+  int oif = getOutboundIf();
118
+  assert(oif >= 0);
119
+  assert(oif < (int)AmConfig::Ifs.size());
120
+  
121
+  contact_uri += AmConfig::Ifs[oif].PublicIP.empty() ? 
122
+    AmConfig::Ifs[oif].LocalSIPIP : AmConfig::Ifs[oif].PublicIP;
123
+  contact_uri += ":" + int2str(AmConfig::Ifs[oif].LocalSIPPort);
124
+  contact_uri += ">" CRLF;
125
+
126
+  return contact_uri;
127
+}
128
+
129
+string AmBasicSipDialog::getRoute() 
130
+{
131
+  string res;
132
+
133
+  if(!outbound_proxy.empty() && (force_outbound_proxy || remote_tag.empty())){
134
+    res += "<" + outbound_proxy + ";lr>";
135
+
136
+    if(!route.empty()) {
137
+      res += ",";
138
+    }
139
+  }
140
+
141
+  res += route;
142
+
143
+  if(!res.empty()) {
144
+    res = SIP_HDR_COLSP(SIP_HDR_ROUTE) + res + CRLF;
145
+  }
146
+
147
+  return res;
148
+}
149
+
150
+/** 
151
+ * Computes, set and return the outbound interface
152
+ * based on remote_uri, next_hop_ip, outbound_proxy, route.
153
+ */
154
+int AmBasicSipDialog::getOutboundIf()
155
+{
156
+  if (outbound_interface >= 0)
157
+    return outbound_interface;
158
+
159
+  if(AmConfig::Ifs.size() == 1){
160
+    return (outbound_interface = 0);
161
+  }
162
+
163
+  // Destination priority:
164
+  // 1. next_hop
165
+  // 2. outbound_proxy (if 1st req or force_outbound_proxy)
166
+  // 3. first route
167
+  // 4. remote URI
168
+  
169
+  string dest_uri;
170
+  string dest_ip;
171
+  string local_ip;
172
+  multimap<string,unsigned short>::iterator if_it;
173
+
174
+  list<host_port> ip_list;
175
+  if(!next_hop.empty() && 
176
+     !parse_next_hop(stl2cstr(next_hop),ip_list) &&
177
+     !ip_list.empty()) {
178
+
179
+    dest_ip = c2stlstr(ip_list.front().host);
180
+  }
181
+  else if(!outbound_proxy.empty() &&
182
+	  (remote_tag.empty() || force_outbound_proxy)) {
183
+    dest_uri = outbound_proxy;
184
+  }
185
+  else if(!route.empty()){
186
+    // parse first route
187
+    sip_header fr;
188
+    fr.value = stl2cstr(route);
189
+    sip_uri* route_uri = get_first_route_uri(&fr);
190
+    if(!route_uri){
191
+      ERROR("Could not parse route (local_tag='%s';route='%s')",
192
+	    local_tag.c_str(),route.c_str());
193
+      goto error;
194
+    }
195
+
196
+    dest_ip = c2stlstr(route_uri->host);
197
+  }
198
+  else {
199
+    dest_uri = remote_uri;
200
+  }
201
+
202
+  if(dest_uri.empty() && dest_ip.empty()) {
203
+    ERROR("No destination found (local_tag='%s')",local_tag.c_str());
204
+    goto error;
205
+  }
206
+  
207
+  if(!dest_uri.empty()){
208
+    sip_uri d_uri;
209
+    if(parse_uri(&d_uri,dest_uri.c_str(),dest_uri.length()) < 0){
210
+      ERROR("Could not parse destination URI (local_tag='%s';dest_uri='%s')",
211
+	    local_tag.c_str(),dest_uri.c_str());
212
+      goto error;
213
+    }
214
+
215
+    dest_ip = c2stlstr(d_uri.host);
216
+  }
217
+
218
+  if(get_local_addr_for_dest(dest_ip,local_ip) < 0){
219
+    ERROR("No local address for dest '%s' (local_tag='%s')",dest_ip.c_str(),local_tag.c_str());
220
+    goto error;
221
+  }
222
+
223
+  if_it = AmConfig::LocalSIPIP2If.find(local_ip);
224
+  if(if_it == AmConfig::LocalSIPIP2If.end()){
225
+    ERROR("Could not find a local interface for resolved local IP (local_tag='%s';local_ip='%s')",
226
+	  local_tag.c_str(), local_ip.c_str());
227
+    goto error;
228
+  }
229
+
230
+  outbound_interface = if_it->second;
231
+  return outbound_interface;
232
+
233
+ error:
234
+  WARN("Error while computing outbound interface: default interface will be used instead.");
235
+  outbound_interface = 0;
236
+  return outbound_interface;
237
+}
238
+
239
+void AmBasicSipDialog::resetOutboundIf()
240
+{
241
+  outbound_interface = -1;
242
+}
243
+
244
+/**
245
+ * Update dialog status from UAC Request that we send.
246
+ */
247
+void AmBasicSipDialog::initFromLocalRequest(const AmSipRequest& req)
248
+{
249
+  if (req.r_uri.length())
250
+    remote_uri = req.r_uri;
251
+
252
+  if(callid.empty()){
253
+    DBG("dialog callid is empty, updating from UACRequest\n");
254
+    callid       = req.callid;
255
+    local_tag    = req.from_tag;
256
+    DBG("local_tag = %s\n",local_tag.c_str());
257
+    user         = req.user;
258
+    domain       = req.domain;
259
+    local_uri    = req.from_uri;
260
+    remote_party = req.to;
261
+    local_party  = req.from;
262
+  }
263
+}
264
+
265
+bool AmBasicSipDialog::onRxReqSanity(const AmSipRequest& req)
266
+{
267
+  // Sanity checks
268
+  if(!remote_tag.empty() && !req.from_tag.empty() &&
269
+     (req.from_tag != remote_tag)){
270
+    DBG("remote_tag = '%s'; req.from_tag = '%s'\n",
271
+	remote_tag.c_str(), req.from_tag.c_str());
272
+    reply_error(req, 481, SIP_REPLY_NOT_EXIST);
273
+    return false;
274
+  }
275
+
276
+  if (r_cseq_i && req.cseq <= r_cseq){
277
+
278
+    if (req.method == SIP_METH_NOTIFY) {
279
+      if (!AmConfig::IgnoreNotifyLowerCSeq) {
280
+	// clever trick to not break subscription dialog usage
281
+	// for implementations which follow 3265 instead of 5057
282
+	string hdrs = SIP_HDR_COLSP(SIP_HDR_RETRY_AFTER)  "0"  CRLF;
283
+
284
+	INFO("remote cseq lower than previous ones - refusing request\n");
285
+	// see 12.2.2
286
+	reply_error(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR, hdrs);
287
+	return false;
288
+      }
289
+    }
290
+    else {
291
+      INFO("remote cseq lower than previous ones - refusing request\n");
292
+      // see 12.2.2
293
+      reply_error(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR);
294
+      return false;
295
+    }
296
+  }
297
+
298
+  r_cseq = req.cseq;
299
+  r_cseq_i = true;
300
+
301
+  return true;
302
+}
303
+
304
+void AmBasicSipDialog::onRxRequest(const AmSipRequest& req)
305
+{
306
+  DBG("AmBasicSipDialog::onRxRequest(req = %s)\n", req.method.c_str());
307
+
308
+  if(!onRxReqSanity(req))
309
+    return;
310
+    
311
+  uas_trans[req.cseq] = req;
312
+    
313
+  // target refresh requests
314
+  if (req.from_uri.length() && 
315
+      (remote_uri.empty() ||
316
+       (req.method == SIP_METH_INVITE || 
317
+	req.method == SIP_METH_UPDATE ||
318
+	req.method == SIP_METH_SUBSCRIBE ||
319
+	req.method == SIP_METH_NOTIFY))) {
320
+    
321
+    // refresh the target
322
+    remote_uri = req.from_uri;
323
+  }
324
+  
325
+  // Dlg not yet initialized?
326
+  if(callid.empty()){
327
+    callid       = req.callid;
328
+    remote_tag   = req.from_tag;
329
+    user         = req.user;
330
+    domain       = req.domain;
331
+    local_uri    = req.r_uri;
332
+    remote_party = req.from;
333
+    local_party  = req.to;
334
+    route        = req.route;
335
+    first_branch = req.via_branch;
336
+    outbound_interface = req.local_if;
337
+  }
338
+
339
+  if(onRxReqStatus(req) && hdl)
340
+    hdl->onSipRequest(req);
341
+}
342
+
343
+bool AmBasicSipDialog::onRxReplyStatus(const AmSipReply& reply, 
344
+				       TransMap::iterator t_uac_it)
345
+{
346
+  /**
347
+   * Error code list from RFC 5057:
348
+   * those error codes terminate the dialog
349
+   *
350
+   * Note: 408, 480 should only terminate
351
+   *       the usage according to RFC 5057.
352
+   */
353
+  switch(reply.code){
354
+  case 404:
355
+  case 408:
356
+  case 410:
357
+  case 416:
358
+  case 480:
359
+  case 482:
360
+  case 483:
361
+  case 484:
362
+  case 485:
363
+  case 502:
364
+  case 604:
365
+    hdl->onRemoteDisappeared(reply);
366
+    break;
367
+  }
368
+  
369
+  return true;
370
+}
371
+
372
+void AmBasicSipDialog::onRxReply(const AmSipReply& reply)
373
+{
374
+  TransMap::iterator t_it = uac_trans.find(reply.cseq);
375
+  if(t_it == uac_trans.end()){
376
+    ERROR("could not find any transaction matching reply: %s\n", 
377
+        ((AmSipReply)reply).print().c_str());
378
+    return;
379
+  }
380
+
381
+  DBG("onRxReply(rep = %u %s): transaction found!\n",
382
+      reply.code, reply.reason.c_str());
383
+
384
+  updateDialogTarget(reply);
385
+  
386
+  Status saved_status = status;
387
+  if(onRxReplyStatus(reply,t_it) && hdl)
388
+    hdl->onSipReply(t_it->second,reply,saved_status);
389
+
390
+  if((reply.code >= 200) && (reply.cseq_method != SIP_METH_INVITE)){
391
+    // final reply
392
+    uac_trans.erase(t_it);
393
+  }
394
+}
395
+
396
+void AmBasicSipDialog::updateDialogTarget(const AmSipReply& reply)
397
+{
398
+  if( (reply.code > 100) && (reply.code < 300) &&
399
+      reply.to_uri.length() &&
400
+      (remote_uri.empty() ||
401
+       (reply.cseq_method.length()==6 &&
402
+	((reply.cseq_method == SIP_METH_INVITE) ||
403
+	 (reply.cseq_method == SIP_METH_UPDATE) ||
404
+	 (reply.cseq_method == SIP_METH_NOTIFY))) ||
405
+       (reply.cseq_method == SIP_METH_SUBSCRIBE)) ) {
406
+    
407
+    remote_uri = reply.to_uri;
408
+  }
409
+}
410
+
411
+void AmBasicSipDialog::updateRouteSet(const string& new_rs)
412
+{
413
+  route = new_rs;
414
+}
415
+
416
+void AmBasicSipDialog::updateRemoteTag(const string& new_rt)
417
+{
418
+  if(!new_rt.empty() && remote_tag.empty()){
419
+    remote_tag = new_rt;
420
+  }
421
+}
422
+
423
+int AmBasicSipDialog::onTxRequest(AmSipRequest& req, int& flags)
424
+{
425
+  if(hdl) hdl->onSendRequest(req,flags);
426
+
427
+  return 0;
428
+}
429
+
430
+int AmBasicSipDialog::onTxReply(const AmSipRequest& req, 
431
+				AmSipReply& reply, int& flags)
432
+{
433
+  if(hdl) hdl->onSendReply(req,reply,flags);
434
+
435
+  return 0;
436
+}
437
+
438
+void AmBasicSipDialog::onReplyTxed(const AmSipRequest& req, 
439
+				   const AmSipReply& reply)
440
+{
441
+  if(hdl) hdl->onReplySent(req, reply);
442
+
443
+  if ((reply.code >= 200) && 
444
+      (reply.cseq_method != SIP_METH_CANCEL)) {
445
+    
446
+    uas_trans.erase(reply.cseq);
447
+  }
448
+}
449
+
450
+void AmBasicSipDialog::onRequestTxed(const AmSipRequest& req)
451
+{
452
+  if(hdl) hdl->onRequestSent(req);
453
+
454
+  if(req.method != SIP_METH_ACK) {
455
+    uac_trans[req.cseq] = req;
456
+    cseq++;
457
+  }
458
+  else {
459
+    // probably never executed, as send_200_ack is used instead of sendRequest
460
+    // note: non-200 ACKs are sent from the transaction layer
461
+    uac_trans.erase(req.cseq);
462
+  }
463
+}
464
+
465
+int AmBasicSipDialog::reply(const AmSipRequest& req,
466
+			    unsigned int  code,
467
+			    const string& reason,
468
+			    const AmMimeBody* body,
469
+			    const string& hdrs,
470
+			    int flags)
471
+{
472
+  TransMap::const_iterator t_it = uas_trans.find(req.cseq);
473
+  if(t_it == uas_trans.end()){
474
+    ERROR("could not find any transaction matching request cseq\n");
475
+    ERROR("request cseq=%i; reply code=%i; callid=%s; local_tag=%s; "
476
+	  "remote_tag=%s\n",
477
+	  req.cseq,code,callid.c_str(),
478
+	  local_tag.c_str(),remote_tag.c_str());
479
+    return -1;
480
+  }
481
+  DBG("reply: transaction found!\n");
482
+    
483
+  string m_hdrs = hdrs;
484
+  AmSipReply reply;
485
+
486
+  reply.code = code;
487
+  reply.reason = reason;
488
+  reply.tt = req.tt;
489
+  reply.to_tag = local_tag;
490
+  reply.hdrs = m_hdrs;
491
+  reply.cseq = req.cseq;
492
+  reply.cseq_method = req.method;
493
+
494
+  if(body != NULL)
495
+    reply.body = *body;
496
+
497
+  if(onTxReply(req,reply,flags)){
498
+    DBG("onTxReply failed\n");
499
+    return -1;
500
+  }
501
+
502
+  if (!(flags & SIP_FLAGS_VERBATIM)) {
503
+    // add Signature
504
+    if (AmConfig::Signature.length())
505
+      reply.hdrs += SIP_HDR_COLSP(SIP_HDR_SERVER) + AmConfig::Signature + CRLF;
506
+  }
507
+
508
+  if ((code < 300) && !(flags & SIP_FLAGS_NOCONTACT)) {
509
+    /* if 300<=code<400, explicit contact setting should be done */
510
+    reply.contact = getContactHdr();
511
+  }
512
+
513
+  int ret = SipCtrlInterface::send(reply);
514
+  if(ret){
515
+    ERROR("Could not send reply: code=%i; reason='%s'; method=%s;"
516
+	  " call-id=%s; cseq=%i\n",
517
+	  reply.code,reply.reason.c_str(),reply.cseq_method.c_str(),
518
+	  reply.callid.c_str(),reply.cseq);
519
+
520
+    return ret;
521
+  }
522
+  else {
523
+    onReplyTxed(req,reply);
524
+  }
525
+
526
+  return ret;
527
+}
528
+
529
+
530
+/* static */
531
+int AmBasicSipDialog::reply_error(const AmSipRequest& req, unsigned int code, 
532
+				  const string& reason, const string& hdrs)
533
+{
534
+  AmSipReply reply;
535
+
536
+  reply.code = code;
537
+  reply.reason = reason;
538
+  reply.tt = req.tt;
539
+  reply.hdrs = hdrs;
540
+  reply.to_tag = AmSession::getNewId();
541
+
542
+  if (AmConfig::Signature.length())
543
+    reply.hdrs += SIP_HDR_COLSP(SIP_HDR_SERVER) + AmConfig::Signature + CRLF;
544
+
545
+  // add transcoder statistics into reply headers
546
+  //addTranscoderStats(reply.hdrs);
547
+
548
+  int ret = SipCtrlInterface::send(reply);
549
+  if(ret){
550
+    ERROR("Could not send reply: code=%i; reason='%s';"
551
+	  " method=%s; call-id=%s; cseq=%i\n",
552
+	  reply.code,reply.reason.c_str(),
553
+	  req.method.c_str(),req.callid.c_str(),req.cseq);
554
+  }
555
+
556
+  return ret;
557
+}
558
+
559
+int AmBasicSipDialog::sendRequest(const string& method, 
560
+				  const AmMimeBody* body,
561
+				  const string& hdrs,
562
+				  int flags)
563
+{
564
+  AmSipRequest req;
565
+
566
+  req.method = method;
567
+  req.r_uri = remote_uri;
568
+
569
+  req.from = SIP_HDR_COLSP(SIP_HDR_FROM) + local_party;
570
+  if(!local_tag.empty())
571
+    req.from += ";tag=" + local_tag;
572
+    
573
+  req.to = SIP_HDR_COLSP(SIP_HDR_TO) + remote_party;
574
+  if(!remote_tag.empty()) 
575
+    req.to += ";tag=" + remote_tag;
576
+    
577
+  req.cseq = cseq;
578
+  req.callid = callid;
579
+    
580
+  req.hdrs = hdrs;
581
+
582
+  req.route = getRoute();
583
+
584
+  if(body != NULL) {
585
+    req.body = *body;
586
+  }
587
+
588
+  onTxRequest(req,flags);
589
+
590
+  if (!(flags & SIP_FLAGS_NOCONTACT)) {
591
+    req.contact = getContactHdr();
592
+  }
593
+
594
+  if (!(flags & SIP_FLAGS_VERBATIM)) {
595
+    // add Signature
596
+    if (AmConfig::Signature.length())
597
+      req.hdrs += SIP_HDR_COLSP(SIP_HDR_USER_AGENT) + AmConfig::Signature + CRLF;
598
+    
599
+    req.hdrs += SIP_HDR_COLSP(SIP_HDR_MAX_FORWARDS) + 
600
+      int2str(AmConfig::MaxForwards) + CRLF;
601
+  }
602
+
603
+  int res = SipCtrlInterface::send(req, remote_tag.empty() ? next_hop : "",
604
+				   outbound_interface);
605
+  if(res) {
606
+    ERROR("Could not send request: method=%s; call-id=%s; cseq=%i\n",
607
+	  req.method.c_str(),req.callid.c_str(),req.cseq);
608
+    return res;
609
+  }
610
+  else {
611
+    onRequestTxed(req);
612
+  }
613
+ 
614
+  return res;
615
+}
0 616
new file mode 100644
... ...
@@ -0,0 +1,342 @@
1
+/*
2
+ * Copyright (C) 2012 Frafos GmbH
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
+#ifndef _AmBasicSipDialog_h_
28
+#define _AmBasicSipDialog_h_
29
+
30
+#include "AmSipMsg.h"
31
+
32
+#include <string>
33
+#include <vector>
34
+#include <map>
35
+using std::string;
36
+
37
+// flags which may be used when sending request/reply
38
+#define SIP_FLAGS_VERBATIM     1 // send request verbatim, 
39
+                                 // i.e. modify as little as possible
40
+
41
+#define SIP_FLAGS_NOAUTH       1<<1 // don't add authentication header
42
+#define SIP_FLAGS_NOCONTACT    1<<2 // don't add contact
43
+
44
+/** \brief SIP transaction representation */
45
+struct AmSipTransaction
46
+{
47
+  string       method;
48
+  unsigned int cseq;
49
+  trans_ticket tt;
50
+
51
+  AmSipTransaction(const string& method, unsigned int cseq, const trans_ticket& tt)
52
+  : method(method),
53
+    cseq(cseq),
54
+    tt(tt)
55
+  {}
56
+
57
+  AmSipTransaction()
58
+  {}
59
+};
60
+
61
+typedef std::map<int,AmSipRequest> TransMap;
62
+
63
+class AmBasicSipEventHandler;
64
+
65
+class AmBasicSipDialog
66
+  : public AmObject
67
+{
68
+public:
69
+  enum Status {	
70
+    Disconnected=0,
71
+    Trying,
72
+    Proceeding,
73
+    Cancelling,
74
+    Early,
75
+    Connected,
76
+    Disconnecting,
77
+    __max_Status
78
+  };
79
+
80
+private:
81
+  static const char* status2str[__max_Status];
82
+
83
+protected:
84
+  Status status;
85
+
86
+  TransMap uas_trans;
87
+  TransMap uac_trans;
88
+
89
+  /** Dialog usages in the sense of RFC 5057 */
90
+  unsigned int usages;
91
+
92
+  AmBasicSipEventHandler* hdl;
93
+
94
+  /**
95
+   * Executed for replies sent by a local UA,
96
+   * right before the reply is passed to the transaction layer.
97
+   */
98
+  virtual int onTxReply(const AmSipRequest& req, AmSipReply& reply, int& flags);
99
+
100
+  /**
101
+   * Executed for requests sent by a local UA,
102
+   * right before the request is passed to the transaction layer.
103
+   */
104
+  virtual int onTxRequest(AmSipRequest& req, int& flags);
105
+
106
+  /**
107
+   * Executed for replies sent by a local UA,
108
+   * after the reply has been successfuly sent.
109
+   */
110
+  virtual void onReplyTxed(const AmSipRequest& req, const AmSipReply& reply);
111
+
112
+  /**
113
+   * Executed for requests sent by a local UA,
114
+   * after the request has been successfuly sent.
115
+   */
116
+  virtual void onRequestTxed(const AmSipRequest& req);
117
+
118
+  /**
119
+   * Basic sanity check on received requests
120
+   *
121
+   * Note: At this point in the processing, 
122
+   *       the request has not been inserted yet
123
+   *       into the uas_trans container.
124
+   *       Thus, reply_error() should be used 
125
+   *       instead of reply() method.
126
+   *       
127
+   * @return true to continue processing, false otherwise
128
+   */
129
+  virtual bool onRxReqSanity(const AmSipRequest& req);
130
+  
131
+  /**
132
+   * Executed from onRxRequest() to allow inherited classes
133
+   * to extend the basic behavior.
134
+   *
135
+   * @return true to continue processing, false otherwise
136
+   */
137
+  virtual bool onRxReqStatus(const AmSipRequest& req) { return true; }
138
+
139
+  /**
140
+   * Executed from onRxReply() to allow inherited classes
141
+   * to extend the basic behavior (deletes the transaction on final reply).
142
+   *
143
+   * @return true to continue processing, false otherwise
144
+   */
145
+  virtual bool onRxReplyStatus(const AmSipReply& reply, 
146
+			       TransMap::iterator t_uac_it);
147
+
148
+public:
149
+
150
+  string user;         // local user
151
+  string domain;       // local domain
152
+
153
+  string local_uri;    // local uri
154
+  string remote_uri;   // remote uri
155
+
156
+
157
+  string callid;
158
+  string remote_tag;
159
+  string local_tag;
160
+  string ext_local_tag;
161
+
162
+  string first_branch;
163
+
164
+  string remote_party; // To/From
165
+  string local_party;  // To/From
166
+
167
+  string route;
168
+  string outbound_proxy;
169
+  bool   force_outbound_proxy;
170
+
171
+  string next_hop;
172
+  bool next_hop_1st_req;
173
+
174
+  int  outbound_interface;
175
+  bool nat_handling;
176
+
177
+  unsigned int cseq; // Local CSeq for next request
178
+  bool r_cseq_i;
179
+  unsigned int r_cseq; // last remote CSeq  
180
+
181
+  AmBasicSipDialog(AmBasicSipEventHandler* h=0);
182
+  virtual ~AmBasicSipDialog();
183
+  
184
+  /** @return UAC request coresponding to cseq or NULL */
185
+  AmSipRequest* getUACTrans(unsigned int t_cseq);
186
+
187
+  /** @return UAS request coresponding to cseq or NULL */
188
+  AmSipRequest* getUASTrans(unsigned int t_cseq);
189
+
190
+  /** @return the method of the corresponding uac request */
191
+  string getUACTransMethod(unsigned int t_cseq);
192
+
193
+  /** @return whether UAC transaction is pending */
194
+  bool   getUACTransPending();
195
+
196
+  /**
197
+   * Getter/Setter basic dialog status
198
+   */
199
+  Status       getStatus() { return status; }
200
+  virtual void setStatus(Status new_status);
201
+
202
+  virtual const char* getStatusStr();
203
+  static const char* getStatusStr(Status st);
204
+  
205
+  unsigned int getUsages() { return usages; }
206
+  void incUsages() { usages++; }
207
+  void decUsages() { usages--; }
208
+
209
+  /**
210
+   * Compute the Contact-HF for the next request
211
+   */
212
+  string getContactHdr();
213
+
214
+  /**
215
+   * Compute the Route-HF for the next request
216
+   */
217
+  string getRoute();
218
+
219
+  /** 
220
+   * Compute, set and return the outbound interface
221
+   * based on remote_uri, next_hop_ip, outbound_proxy, route.
222
+   */
223
+  int getOutboundIf();
224
+
225
+  /**
226
+   * Reset outbound_interface to default value (-1).
227
+   */
228
+  void resetOutboundIf();
229
+
230
+  /**
231
+   * Set outbound_interface to specific value (-1 = default).
232
+   */
233
+  //void setOutboundInterface(int interface_id);
234
+
235
+  /** Initialize dialog from locally originated UAC request */
236
+  void initFromLocalRequest(const AmSipRequest& req);
237
+
238
+  /**
239
+   * Executed for requests received by the local UA.
240
+   */
241
+  void onRxRequest(const AmSipRequest& req);
242
+
243
+  /**
244
+   * Executed for replies received by the local UA.
245
+   */
246
+  void onRxReply(const AmSipReply& reply);
247
+
248
+  /**
249
+   * Updates remote_uri if necessary.
250
+   *
251
+   * Note: this method is offered for inherited classes
252
+   *       implementing dialog functionnalities. It is
253
+   *       not used by the basic class.
254
+   */
255
+  void updateDialogTarget(const AmSipReply& reply);
256
+
257
+  void updateRouteSet(const string& new_rs);
258
+  void updateRemoteTag(const string& new_rt);
259
+
260
+
261
+  /** @return 0 on success */
262
+  virtual int reply(const AmSipRequest& req,
263
+		    unsigned int  code, 
264
+		    const string& reason,
265
+		    const AmMimeBody* body = NULL,
266
+		    const string& hdrs = "",
267
+		    int flags = 0);
268
+
269
+  /** @return 0 on success */
270
+  virtual int sendRequest(const string& method, 
271
+			  const AmMimeBody* body = NULL,
272
+			  const string& hdrs = "",
273
+			  int flags = 0);
274
+
275
+  /**
276
+   * This method should only be used to send responses
277
+   * to requests which are not referenced by any dialog.
278
+   *
279
+   * WARNING: If the request has already been referenced 
280
+   * (see uas_trans), this method cannot mark the request 
281
+   * as replied, thus leaving it in the pending state forever.
282
+   */
283
+  static int reply_error(const AmSipRequest& req,
284
+			 unsigned int  code,
285
+			 const string& reason,
286
+			 const string& hdrs = "");
287
+
288
+  /* dump transaction information (DBG) */
289
+  void dump();
290
+};
291
+
292
+/**
293
+ * \brief base class for SIP request/reply event handler
294
+ */
295
+class AmBasicSipEventHandler
296
+{
297
+ public:
298
+
299
+  /** Hook called when a request has been received */
300
+  virtual void onSipRequest(const AmSipRequest& req) {}
301
+
302
+  /** Hook called when a reply has been received */
303
+  virtual void onSipReply(const AmSipRequest& req,
304
+			  const AmSipReply& reply,
305
+			  AmBasicSipDialog::Status old_status) {}
306
+
307
+  /** Hook called before a request is sent */
308
+  virtual void onSendRequest(AmSipRequest& req, int& flags) {}
309
+    
310
+  /** Hook called before a reply is sent */
311
+  virtual void onSendReply(const AmSipRequest& req, 
312
+			   AmSipReply& reply, int& flags) {}
313
+
314
+  /** Hook called after a request has been sent */
315
+  virtual void onRequestSent(const AmSipRequest& req) {}
316
+
317
+  /** Hook called after a reply has been sent */
318
+  virtual void onReplySent(const AmSipRequest& req, const AmSipReply& reply) {}
319
+    
320
+  /**
321
+   * Hook called when the all dialog usages should be terminated
322
+   * after a reply received from the far end, or a locally generated
323
+   * timeout (408).
324
+   */
325
+  virtual void onRemoteDisappeared(const AmSipReply& reply) {}
326
+
327
+  /** 
328
+   * Hook called when the all dialog usages should be terminated 
329
+   * before a local reply is sent.
330
+   */
331
+  virtual void onLocalTerminate(const AmSipReply& reply) {}
332
+
333
+  /** 
334
+   * Hook called when either a received request or 
335
+   * reply has been rejected by the local SIP UA layer.
336
+   */
337
+  virtual void onFailure() {}
338
+
339
+  virtual ~AmBasicSipEventHandler() {}
340
+};
341
+
342
+#endif
... ...
@@ -156,7 +156,7 @@ int AmOfferAnswer::onRequestIn(const AmSipRequest& req)
156 156
     clearTransitionalState();
157 157
   }
158 158
 
159
-  return 0;
159
+  return err_code ? -1 : 0;
160 160
 }
161 161
 
162 162
 int AmOfferAnswer::onReplyIn(const AmSipReply& reply)
... ...
@@ -363,7 +363,7 @@ bool AmSession::processingCycle() {
363 363
 
364 364
   DBG("vv S [%s|%s] %s, %s, %i UACTransPending vv\n",
365 365
       dlg.callid.c_str(),getLocalTag().c_str(),
366
-      dlgStatusStr(dlg.getStatus()),
366
+      dlg.getStatusStr(),
367 367
       sess_stopped.get()?"stopped":"running",
368 368
       dlg.getUACTransPending());
369 369
 
... ...
@@ -381,7 +381,7 @@ bool AmSession::processingCycle() {
381 381
       
382 382
       DBG("^^ S [%s|%s] %s, %s, %i UACTransPending ^^\n",
383 383
 	  dlg.callid.c_str(),getLocalTag().c_str(),
384
-	  dlgStatusStr(dlg_status),
384
+	  AmBasicSipDialog::getStatusStr(dlg_status),
385 385
 	  s_stopped?"stopped":"running",
386 386
 	  dlg.getUACTransPending());
387 387
       
... ...
@@ -429,7 +429,7 @@ bool AmSession::processingCycle() {
429 429
 
430 430
     DBG("^^ S [%s|%s] %s, %s, %i UACTransPending ^^\n",
431 431
 	dlg.callid.c_str(),getLocalTag().c_str(),
432
-	dlgStatusStr(dlg.getStatus()),
432
+	dlg.getStatusStr(),
433 433
 	sess_stopped.get()?"stopped":"running",
434 434
 	dlg.getUACTransPending());
435 435
 
... ...
@@ -814,7 +814,7 @@ void AmSession::onSipRequest(const AmSipRequest& req)
814 814
 }
815 815
 
816 816
 void AmSession::onSipReply(const AmSipReply& reply,
817
-			   AmSipDialog::Status old_dlg_status)
817
+			   AmBasicSipDialog::Status old_dlg_status)
818 818
 {
819 819
   CALL_EVENT_H(onSipReply, reply, old_dlg_status);
820 820
 
... ...
@@ -827,12 +827,12 @@ void AmSession::onSipReply(const AmSipReply& reply,
827 827
 
828 828
   if (old_dlg_status != dlg.getStatus()) {
829 829
     DBG("Dialog status changed %s -> %s (stopped=%s) \n", 
830
-	dlgStatusStr(old_dlg_status), 
831
-	dlgStatusStr(dlg.getStatus()),
830
+	AmBasicSipDialog::getStatusStr(old_dlg_status), 
831
+	dlg.getStatusStr(),
832 832
 	sess_stopped.get() ? "true" : "false");
833 833
   } else {
834 834
     DBG("Dialog status stays %s (stopped=%s)\n", 
835
-	dlgStatusStr(old_dlg_status), 
835
+	AmBasicSipDialog::getStatusStr(old_dlg_status), 
836 836
 	sess_stopped.get() ? "true" : "false");
837 837
   }
838 838
 }
... ...
@@ -841,8 +841,7 @@ void AmSession::onSipReply(const AmSipReply& reply,
841 841
 
842 842
 void AmSession::onInvite2xx(const AmSipReply& reply)
843 843
 {
844
-  if(dlg.getUACTrans(reply.cseq))
845
-    dlg.send_200_ack(reply.cseq);
844
+  dlg.send_200_ack(reply.cseq);
846 845
 }
847 846
 
848 847
 void AmSession::onRemoteDisappeared(const AmSipReply&) {
... ...
@@ -1193,32 +1192,31 @@ void AmSession::setOnHold(bool hold)
1193 1192
   unlockAudio();
1194 1193
 }
1195 1194
 
1196
-void AmSession::onFailure(AmSipDialogEventHandler::FailureCause cause, 
1197
-    const AmSipRequest *req, const AmSipReply *rpl)
1195
+void AmSession::onFailure()
1198 1196
 {
1199
-  switch (cause) {
1200
-    case FAIL_REL100_421:
1201
-    case FAIL_REL100_420:
1202
-      if (rpl) {
1203
-        dlg.cancel();
1204
-        if (dlg.getStatus() < AmSipDialog::Connected)
1205
-          setStopped();
1206
-      } else if (req) {
1207
-        if (cause == FAIL_REL100_421) {
1208
-          dlg.reply(*req, 421, SIP_REPLY_EXTENSION_REQUIRED, NULL,
1209
-              SIP_HDR_COLSP(SIP_HDR_REQUIRE) SIP_EXT_100REL CRLF);
1210
-        } else {
1211
-          dlg.reply(*req, 420, SIP_REPLY_BAD_EXTENSION, NULL,
1212
-              SIP_HDR_COLSP(SIP_HDR_UNSUPPORTED) SIP_EXT_100REL CRLF);
1213
-        }
1214
-        /* finally, stop session if running */
1215
-        if (dlg.getStatus() < AmSipDialog::Connected)
1216
-          setStopped();
1217
-      }
1218
-      break;
1219
-    default:
1220
-      break;
1221
-  }
1197
+  // switch (cause) {
1198
+  //   case FAIL_REL100_421:
1199
+  //   case FAIL_REL100_420:
1200
+  //     if (rpl) {
1201
+  //       dlg.cancel();
1202
+  //       if (dlg.getStatus() < AmSipDialog::Connected)
1203
+  //         setStopped();
1204
+  //     } else if (req) {
1205
+  //       if (cause == FAIL_REL100_421) {
1206
+  //         dlg.reply(*req, 421, SIP_REPLY_EXTENSION_REQUIRED, NULL,
1207
+  //             SIP_HDR_COLSP(SIP_HDR_REQUIRE) SIP_EXT_100REL CRLF);
1208
+  //       } else {
1209
+  //         dlg.reply(*req, 420, SIP_REPLY_BAD_EXTENSION, NULL,
1210
+  //             SIP_HDR_COLSP(SIP_HDR_UNSUPPORTED) SIP_EXT_100REL CRLF);
1211
+  //       }
1212
+  //       /* finally, stop session if running */
1213
+  //       if (dlg.getStatus() < AmSipDialog::Connected)
1214
+  //         setStopped();
1215
+  //     }
1216
+  //     break;
1217
+  //   default:
1218
+  //     break;
1219
+  // }
1222 1220
 }
1223 1221
 
1224 1222
 // Utility for basic NAT handling: allow the config file to specify the IP
... ...
@@ -524,8 +524,7 @@ public:
524 524
   /** answer for a locally sent PRACK is received */
525 525
   virtual void onPrack2xx(const AmSipReply &);
526 526
 
527
-  virtual void onFailure(AmSipDialogEventHandler::FailureCause cause, 
528
-      const AmSipRequest*, const AmSipReply*);
527
+  virtual void onFailure();
529 528
   
530 529
   virtual void onNoAck(unsigned int cseq);
531 530
   virtual void onNoPrack(const AmSipRequest &req, const AmSipReply &rpl);
... ...
@@ -60,147 +60,61 @@ static void addTranscoderStats(string &hdrs)
60 60
   }
61 61
 }
62 62
 
63
-const char* __dlg_status2str[AmSipDialog::__max_Status]  = {
64
-  "Disconnected",
65
-  "Trying",
66
-  "Proceeding",
67
-  "Cancelling",
68
-  "Early",
69
-  "Connected",
70
-  "Disconnecting"
71
-};
72
-
73
-const char* dlgStatusStr(AmSipDialog::Status st)
74
-{
75
-  if((st < 0) || (st >= AmSipDialog::__max_Status))
76
-    return "Invalid";
77
-  else
78
-    return __dlg_status2str[st];
79
-}
80
-
81
-const char* AmSipDialog::getStatusStr()
82
-{
83
-  return dlgStatusStr(status);
84
-}
85
-
86 63
 AmSipDialog::AmSipDialog(AmSipDialogEventHandler* h)
87
-  : status(Disconnected),oa(this),rel100(this,h),
64
+  : AmBasicSipDialog(h),oa(this),rel100(this,h),
88 65
     offeranswer_enabled(true),
89 66
     early_session_started(false),session_started(false),
90
-    cseq(10),r_cseq_i(false),hdl(h),
91 67
     pending_invites(0),cancel_pending(false),
92
-    outbound_proxy(AmConfig::OutboundProxy),
93
-    force_outbound_proxy(AmConfig::ForceOutboundProxy),
94
-    next_hop(AmConfig::NextHop),
95
-    next_hop_1st_req(AmConfig::NextHop1stReq),
96
-    outbound_interface(-1),
97 68
     sdp_local(), sdp_remote()
98 69
 {
99
-  assert(h);
100 70
 }
101 71
 
102 72
 AmSipDialog::~AmSipDialog()
103 73
 {
104
-  DBG("callid = %s\n",callid.c_str());
105
-  DBG("local_tag = %s\n",local_tag.c_str());
106
-  DBG("uac_trans.size() = %u\n",(unsigned int)uac_trans.size());
107
-  if(uac_trans.size()){
108
-    for(TransMap::iterator it = uac_trans.begin();
109
-	it != uac_trans.end(); it++){
110
-	    
111
-      DBG("    cseq = %i; method = %s\n",it->first,it->second.method.c_str());
112
-    }
113
-  }
114
-  DBG("uas_trans.size() = %u\n",(unsigned int)uas_trans.size());
115
-  if(uas_trans.size()){
116
-    for(TransMap::iterator it = uas_trans.begin();
117
-	it != uas_trans.end(); it++){
118
-	    
119
-      DBG("    cseq = %i; method = %s\n",it->first,it->second.method.c_str());
120
-    }
121
-  }
122
-}
123
-
124
-void AmSipDialog::setStatus(Status new_status) {
125
-  DBG("setting SIP dialog status: %s->%s\n",
126
-      getStatusStr(), dlgStatusStr(new_status));
127
-
128
-  status = new_status;
129 74
 }
130 75
 
131
-void AmSipDialog::onRxRequest(const AmSipRequest& req)
76
+bool AmSipDialog::onRxReqSanity(const AmSipRequest& req)
132 77
 {
133
-  DBG("AmSipDialog::onRxRequest(req = %s)\n", req.method.c_str());
134
-
135
-  if ((req.method != SIP_METH_ACK) && (req.method != SIP_METH_CANCEL)) {
136
-
137
-    // Sanity checks
138
-    if (r_cseq_i && req.cseq <= r_cseq){
139
-      string hdrs; bool i = false;
140
-      if (req.method == SIP_METH_NOTIFY) {
141
-	if (AmConfig::IgnoreNotifyLowerCSeq)
142
-	  i = true;
143
-	else
144
-	  // clever trick to not break subscription dialog usage
145
-	  // for implementations which follow 3265 instead of 5057
146
-	  hdrs = SIP_HDR_COLSP(SIP_HDR_RETRY_AFTER)  "0"  CRLF;
147
-      }
78
+  if (req.method == SIP_METH_ACK) {
79
+    return true;
80
+  }
148 81
 
149
-      if (!i) {
150
-	INFO("remote cseq lower than previous ones - refusing request\n");
151
-	// see 12.2.2
152
-	reply_error(req, 500, SIP_REPLY_SERVER_INTERNAL_ERROR, hdrs);
153
-	return;
154
-      }
82
+  if (req.method == SIP_METH_CANCEL) {
83
+
84
+    if (uas_trans.find(req.cseq) == uas_trans.end()) {
85
+      reply_error(req,481,SIP_REPLY_NOT_EXIST);
86
+      return false;
155 87
     }
156 88
 
157
-    if (req.method == SIP_METH_INVITE) {
158
-      bool pending = pending_invites;
159
-      if (offeranswer_enabled) {
160
-	  // not sure this is needed here: could be in AmOfferAnswer as well
161
-	pending |= ((oa.getState() != AmOfferAnswer::OA_None) &&
162
-		    (oa.getState() != AmOfferAnswer::OA_Completed));
163
-      }
89
+    return true;
90
+  }
164 91
 
165
-      if (pending) {
166
-	reply_error(req, 491, SIP_REPLY_PENDING,
167
-		    SIP_HDR_COLSP(SIP_HDR_RETRY_AFTER) 
168
-		    + int2str(get_random() % 10) + CRLF);
169
-	return;
170
-      }
92
+  if(!AmBasicSipDialog::onRxReqSanity(req))
93
+    return false;
171 94
 
172
-      pending_invites++;
173
-    }
174
-    
175
-    r_cseq = req.cseq;
176
-    r_cseq_i = true;
177
-    uas_trans[req.cseq] = AmSipTransaction(req.method,req.cseq,req.tt);
178
-    
179
-    // target refresh requests
180
-    if (req.from_uri.length() && 
181
-	(req.method == SIP_METH_INVITE || 
182
-	 req.method == SIP_METH_UPDATE ||
183
-	 req.method == SIP_METH_SUBSCRIBE ||
184
-	 req.method == SIP_METH_NOTIFY)) {
185
-
186
-      // refresh the target
187
-      remote_uri = req.from_uri;
95
+  if (req.method == SIP_METH_INVITE) {
96
+    bool pending = pending_invites;
97
+    if (offeranswer_enabled) {
98
+      // not sure this is needed here: could be in AmOfferAnswer as well
99
+      pending |= ((oa.getState() != AmOfferAnswer::OA_None) &&
100
+		  (oa.getState() != AmOfferAnswer::OA_Completed));
188 101
     }
189 102
 
190
-    // Dlg not yet initialized?
191
-    if(callid.empty()){
192
-      callid       = req.callid;