Browse code

oa: isolate offer/answer processing from AmSipDialog

- changed also the onSendRequest handlers everywhere to be consistent with onSendReply.
- event handlers for sessions and extentions are called at the same point to enable a more generic handling in the future.

Raphael Coeffic authored on 01/12/2011 09:25:53
Showing 12 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,456 @@
1
+/*
2
+ * Copyright (C) 2010-2011 Raphael Coeffic
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
+/** @file AmOfferAnswer.cpp */
28
+
29
+#include "AmOfferAnswer.h"
30
+#include "AmSipDialog.h"
31
+#include "AmSipHeaders.h"
32
+#include "log.h"
33
+
34
+#include <assert.h>
35
+
36
+const char* __dlg_oa_status2str[AmOfferAnswer::__max_OA]  = {
37
+    "None",
38
+    "OfferRecved",
39
+    "OfferSent",
40
+    "Completed"
41
+};
42
+
43
+static const char* getOAStateStr(AmOfferAnswer::OAState st) {
44
+  if((st < 0) || (st >= AmOfferAnswer::__max_OA))
45
+    return "Invalid";
46
+  else
47
+    return __dlg_oa_status2str[st];
48
+}
49
+
50
+
51
+AmOfferAnswer::AmOfferAnswer(AmSipDialog* dlg)
52
+  : state(OA_None), 
53
+    cseq(0),
54
+    sdp_remote(),
55
+    sdp_local(),
56
+    dlg(dlg)
57
+{
58
+  
59
+}
60
+
61
+AmOfferAnswer::OAState AmOfferAnswer::getState()
62
+{
63
+  return state;
64
+}
65
+
66
+void AmOfferAnswer::setState(AmOfferAnswer::OAState n_st)
67
+{
68
+  DBG("setting SIP dialog O/A status: %s->%s\n",
69
+      getOAStateStr(state), getOAStateStr(n_st));
70
+  state = n_st;
71
+}
72
+
73
+const AmSdp& AmOfferAnswer::getLocalSdp()
74
+{
75
+  return sdp_local;
76
+}
77
+
78
+const AmSdp& AmOfferAnswer::getRemoteSdp()
79
+{
80
+  return sdp_remote;
81
+}
82
+
83
+/** State maintenance */
84
+void AmOfferAnswer::saveState()
85
+{
86
+  saved_state = state;
87
+}
88
+
89
+int AmOfferAnswer::checkStateChange()
90
+{
91
+  int ret = 0;
92
+
93
+  if((saved_state != state) &&
94
+     (state == OA_Completed)) {
95
+
96
+    ret = dlg->onSdpCompleted();
97
+  }
98
+
99
+  return ret;
100
+}
101
+
102
+void AmOfferAnswer::clear()
103
+{
104
+  setState(OA_None);
105
+  cseq  = 0;
106
+  sdp_remote.clear();
107
+  sdp_local.clear();
108
+}
109
+
110
+void AmOfferAnswer::clearTransitionalState()
111
+{
112
+  if(state != OA_Completed){
113
+    clear();
114
+  }
115
+}
116
+
117
+int AmOfferAnswer::onRequestIn(const AmSipRequest& req)
118
+{
119
+  saveState();
120
+
121
+  const char* err_txt  = NULL;
122
+  int         err_code = 0;
123
+
124
+  if((req.method == SIP_METH_INVITE || 
125
+      req.method == SIP_METH_UPDATE || 
126
+      req.method == SIP_METH_ACK ||
127
+      req.method == SIP_METH_PRACK) &&
128
+     !req.body.empty() && 
129
+     (req.content_type == SIP_APPLICATION_SDP)) {
130
+
131
+    err_code = onRxSdp(req.cseq,req.body,&err_txt);
132
+  }
133
+
134
+  if(checkStateChange()){
135
+    err_code = 500;
136
+    err_txt = "internal error";
137
+  }
138
+
139
+  if(err_code){
140
+    if( req.method != SIP_METH_ACK ){ // INVITE || UPDATE || PRACK
141
+      dlg->reply(req,err_code,err_txt);
142
+    }
143
+    else { // ACK
144
+      // TODO: only if reply to initial INVITE (if re-INV, app should decide)
145
+      DBG("error %i with SDP received in ACK request: sending BYE\n",err_code);
146
+      dlg->bye();
147
+    }
148
+  }
149
+
150
+  if((req.method == SIP_METH_ACK) &&
151
+     (req.cseq == cseq)){
152
+    // 200 ACK received:
153
+    //  -> reset OA state
154
+    DBG("200 ACK received: resetting OA state");
155
+    clearTransitionalState();
156
+  }
157
+
158
+  return 0;
159
+}
160
+
161
+int AmOfferAnswer::onReplyIn(const AmSipReply& reply)
162
+{
163
+  const char* err_txt  = NULL;
164
+  int         err_code = 0;
165
+
166
+  saveState();
167
+
168
+  if((reply.cseq_method == SIP_METH_INVITE || 
169
+      reply.cseq_method == SIP_METH_UPDATE || 
170
+      reply.cseq_method == SIP_METH_PRACK) &&
171
+     !reply.body.empty() && 
172
+     (reply.content_type == SIP_APPLICATION_SDP)) {
173
+
174
+    if(((state == OA_Completed) ||
175
+	(state == OA_OfferRecved)) &&
176
+       (reply.cseq == cseq)) {
177
+      
178
+      DBG("ignoring subsequent SDP reply within the same transaction\n");
179
+      DBG("this usually happens when 183 and 200 have SDP\n");
180
+    }
181
+    else {
182
+      err_code = onRxSdp(reply.cseq,reply.body,&err_txt);
183
+    }
184
+  }
185
+
186
+  checkStateChange();
187
+
188
+  if( (reply.code >= 300) &&
189
+      (reply.cseq_method != SIP_METH_INVITE) &&
190
+      (reply.cseq == cseq) ) {
191
+
192
+    // final error reply to non-INVITE transaction:
193
+    //  -> cleanup OA state
194
+    DBG("after %u reply to %s: resetting OA state\n",
195
+	reply.code, reply.cseq_method.c_str());
196
+    clearTransitionalState();
197
+  }
198
+
199
+
200
+  if(err_code){
201
+    // TODO: only if initial INVITE (if re-INV, app should decide)
202
+    DBG("error %i (%s) with SDP received in %i reply: sending ACK+BYE\n",
203
+	err_code,err_txt?err_txt:"none",reply.code);
204
+    dlg->bye();
205
+  }
206
+
207
+  return 0;
208
+}
209
+
210
+int AmOfferAnswer::onRxSdp(unsigned int m_cseq, const string& body, const char** err_txt)
211
+{
212
+  DBG("entering onRxSdp(), oa_state=%s\n", getOAStateStr(state));
213
+  OAState old_oa_state = state;
214
+
215
+  int err_code = 0;
216
+  assert(err_txt);
217
+
218
+  if(sdp_remote.parse(body.c_str())){
219
+    err_code = 400;
220
+    *err_txt = "session description parsing failed";
221
+  }
222
+  else if(sdp_remote.media.empty()){
223
+    err_code = 400;
224
+    *err_txt = "no media line found in SDP message";
225
+  }
226
+
227
+  if(err_code == 0) {
228
+
229
+    switch(state) {
230
+    case OA_None:
231
+    case OA_Completed:
232
+      setState(OA_OfferRecved);
233
+      cseq = m_cseq;
234
+      break;
235
+      
236
+    case OA_OfferSent:
237
+      setState(OA_Completed);
238
+      break;
239
+
240
+    case OA_OfferRecved:
241
+      err_code = 400;// TODO: check correct error code
242
+      *err_txt = "pending SDP offer";
243
+      break;
244
+
245
+    default:
246
+      assert(0);
247
+      break;
248
+    }
249
+  }
250
+
251
+  if(err_code != 0) {
252
+    clear();
253
+  }
254
+
255
+  DBG("oa_state: %s -> %s\n", getOAStateStr(old_oa_state), getOAStateStr(state));
256
+
257
+  return err_code;
258
+}
259
+
260
+int AmOfferAnswer::onTxSdp(unsigned int m_cseq, const string& body)
261
+{
262
+  // assume that the payload is ok if it is not empty.
263
+  // (do not parse again self-generated SDP)
264
+  if(body.empty()){
265
+    return -1;
266
+  }
267
+
268
+  switch(state) {
269
+
270
+  case OA_None:
271
+  case OA_Completed:
272
+    setState(OA_OfferSent);
273
+    cseq = m_cseq;
274
+    break;
275
+
276
+  case OA_OfferRecved:
277
+    setState(OA_Completed);
278
+    break;
279
+
280
+  case OA_OfferSent:
281
+    // There is already a pending offer!!!
282
+    DBG("There is already a pending offer, onTxSdp fails\n");
283
+    return -1;
284
+
285
+  default:
286
+    break;
287
+  }
288
+
289
+  return 0;
290
+}
291
+
292
+int AmOfferAnswer::onRequestOut(AmSipRequest& req)
293
+{
294
+  bool generate_sdp = req.body.empty() 
295
+    && (req.content_type == SIP_APPLICATION_SDP);
296
+
297
+  bool has_sdp = !req.body.empty() 
298
+    && (req.content_type == SIP_APPLICATION_SDP);
299
+
300
+  if (!generate_sdp && !has_sdp && 
301
+      ((req.method == SIP_METH_PRACK) ||
302
+       (req.method == SIP_METH_ACK))) {
303
+    generate_sdp = (state == OA_OfferRecved);
304
+  }
305
+
306
+  saveState();
307
+
308
+  if (generate_sdp) {
309
+    if (!getSdpBody(req.body)){
310
+      req.content_type = SIP_APPLICATION_SDP;
311
+      has_sdp = true;
312
+    }
313
+    else {
314
+      return -1;
315
+    }
316
+  }
317
+
318
+  if(has_sdp && (onTxSdp(req.cseq,req.body) != 0)){
319
+    DBG("onTxSdp() failed\n");
320
+    return -1;
321
+  }
322
+
323
+  return 0;
324
+}
325
+
326
+int AmOfferAnswer::onReplyOut(AmSipReply& reply)
327
+{
328
+  bool generate_sdp = reply.body.empty() 
329
+    && (reply.content_type == SIP_APPLICATION_SDP);
330
+
331
+  bool has_sdp = !reply.body.empty() 
332
+    && (reply.content_type == SIP_APPLICATION_SDP);
333
+
334
+  if (!has_sdp && !generate_sdp) {
335
+    // let's see whether we should force SDP or not.
336
+
337
+    if (reply.cseq_method == SIP_METH_INVITE){
338
+      
339
+      if ((reply.code == 183) 
340
+	  || ((reply.code >= 200) && (reply.code < 300))) {
341
+	
342
+	// either offer received or no offer at all:
343
+	//  -> force SDP
344
+	generate_sdp = (state == OA_OfferRecved) 
345
+	  || (state == OA_None);
346
+      }
347
+    }
348
+    else if (reply.cseq_method == SIP_METH_UPDATE) {
349
+
350
+      if ((reply.code >= 200) &&
351
+	  (reply.code < 300)) {
352
+	
353
+	// offer received:
354
+	//  -> force SDP
355
+	generate_sdp = (state == OA_OfferRecved);
356
+      }
357
+    }
358
+  }
359
+  
360
+  saveState();
361
+
362
+  if (generate_sdp) {
363
+    if(!getSdpBody(reply.body)) {
364
+      reply.content_type = SIP_APPLICATION_SDP;
365
+      has_sdp = true;
366
+    }
367
+    else {
368
+      return -1;
369
+    }
370
+  }
371
+
372
+  if (has_sdp && (onTxSdp(reply.cseq,reply.body) != 0)) {
373
+    
374
+    DBG("onTxSdp() failed\n");
375
+    return -1;
376
+  }
377
+
378
+  return 0;
379
+}
380
+
381
+int AmOfferAnswer::onRequestSent(const AmSipRequest& req)
382
+{
383
+  int ret = checkStateChange();
384
+
385
+  if((req.method == SIP_METH_ACK) &&
386
+     (req.cseq == cseq)) {
387
+
388
+    // transaction has been removed:
389
+    //  -> cleanup OA state
390
+    DBG("200 ACK sent: resetting OA state\n");
391
+    clearTransitionalState();
392
+  }
393
+
394
+  return ret;
395
+}
396
+
397
+int AmOfferAnswer::onReplySent(const AmSipReply& reply)
398
+{
399
+  int ret = checkStateChange();
400
+
401
+  // final answer to non-invite req that triggered O/A transaction
402
+  if( (reply.code >= 200) &&
403
+      (reply.cseq_method != SIP_METH_CANCEL) &&
404
+      (reply.cseq == cseq) &&
405
+      (reply.cseq_method != SIP_METH_INVITE) ) {
406
+
407
+    // transaction has been removed:
408
+    //  -> cleanup OA state
409
+    DBG("transaction finished by final reply %u: resetting OA state\n", reply.cseq);
410
+    clearTransitionalState();
411
+  }
412
+  
413
+  return ret;
414
+}
415
+
416
+int AmOfferAnswer::getSdpBody(string& sdp_body)
417
+{
418
+    switch(state){
419
+    case OA_None:
420
+    case OA_Completed:
421
+      if(dlg->getSdpOffer(sdp_local)){
422
+	sdp_local.print(sdp_body);
423
+      }
424
+      else {
425
+	DBG("No SDP Offer.\n");
426
+	return -1;
427
+      }
428
+      break;
429
+    case OA_OfferRecved:
430
+      if(dlg->getSdpAnswer(sdp_remote,sdp_local)){
431
+	sdp_local.print(sdp_body);
432
+      }
433
+      else {
434
+	DBG("No SDP Answer.\n");
435
+	return -1;
436
+      }
437
+      break;
438
+      
439
+    case OA_OfferSent:
440
+      DBG("Still waiting for a reply\n");
441
+      return -1;
442
+
443
+    default: 
444
+      break;
445
+    }
446
+
447
+    return 0;
448
+}
449
+
450
+void AmOfferAnswer::onNoAck(unsigned int ack_cseq)
451
+{
452
+  if(ack_cseq == cseq){
453
+    DBG("ACK timeout: resetting OA state\n");
454
+    clearTransitionalState();
455
+  }
456
+}
0 457
new file mode 100644
... ...
@@ -0,0 +1,88 @@
1
+/*
2
+ * Copyright (C) 2010-2011 Raphael Coeffic
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
+/** @file AmOfferAnswer.h */
28
+#ifndef AmOfferAnswer_h
29
+#define AmOfferAnswer_h
30
+
31
+#include "AmSdp.h"
32
+#include "AmSipMsg.h"
33
+
34
+class AmSipDialog;
35
+
36
+class AmOfferAnswer 
37
+{
38
+public:
39
+  enum OAState {
40
+    OA_None=0,
41
+    OA_OfferRecved,
42
+    OA_OfferSent,
43
+    OA_Completed,
44
+    __max_OA
45
+  };
46
+
47
+private:
48
+  OAState      state;
49
+  OAState      saved_state;
50
+  unsigned int cseq;
51
+  AmSdp        sdp_remote;
52
+  AmSdp        sdp_local;
53
+
54
+  AmSipDialog* dlg;
55
+
56
+  /** State maintenance */
57
+  void saveState();
58
+  int  checkStateChange();
59
+
60
+  /** SDP handling */
61
+  int  onRxSdp(unsigned int m_cseq, const string& body, const char** err_txt);
62
+  int  onTxSdp(unsigned int m_cseq, const string& body);
63
+  int  getSdpBody(string& sdp_body);
64
+
65
+public:
66
+  /** Constructor */
67
+  AmOfferAnswer(AmSipDialog* dlg);
68
+
69
+  /** Accessors */
70
+  OAState getState();
71
+  void setState(OAState n_st);
72
+  const AmSdp& getLocalSdp();
73
+  const AmSdp& getRemoteSdp();
74
+
75
+  void clear();
76
+  void clearTransitionalState();
77
+
78
+  /** Event handlers */
79
+  int onRequestIn(const AmSipRequest& req);
80
+  int onReplyIn(const AmSipReply& reply);
81
+  int onRequestOut(AmSipRequest& req);
82
+  int onReplyOut(AmSipReply& reply);
83
+  int onRequestSent(const AmSipRequest& req);
84
+  int onReplySent(const AmSipReply& reply);
85
+  void onNoAck(unsigned int ack_cseq);
86
+};
87
+
88
+#endif
... ...
@@ -936,10 +936,9 @@ void AmSession::onSystemEvent(AmSystemEvent* ev) {
936 936
   }
937 937
 }
938 938
 
939
-void AmSession::onSendRequest(const string& method, const string& content_type,
940
-			      const string& body, string& hdrs, int flags, unsigned int cseq)
939
+void AmSession::onSendRequest(AmSipRequest& req, int flags)
941 940
 {
942
-  CALL_EVENT_H(onSendRequest,method,content_type,body,hdrs,flags,cseq);
941
+  CALL_EVENT_H(onSendRequest,req,flags);
943 942
 }
944 943
 
945 944
 void AmSession::onSendReply(AmSipReply& reply, int flags)
... ...
@@ -596,12 +596,7 @@ public:
596 596
   virtual void onSessionTimeout();
597 597
 
598 598
   /* Called by AmSipDialog when a request is sent */
599
-  virtual void onSendRequest(const string& method,
600
-			     const string& content_type,
601
-			     const string& body,
602
-			     string& hdrs,
603
-			     int flags,
604
-			     unsigned int cseq);
599
+  virtual void onSendRequest(AmSipRequest& req, int flags);
605 600
 
606 601
   /** Called by AmSipDialog when a reply is sent */
607 602
   virtual void onSendReply(AmSipReply& reply, int flags);
... ...
@@ -59,12 +59,7 @@ bool AmSessionEventHandler::onSipRplTimeout(const AmSipRequest &,
59 59
   return false;
60 60
 }
61 61
 
62
-bool AmSessionEventHandler::onSendRequest(const string& method, 
63
-					  const string& content_type,
64
-					  const string& body,
65
-					  string& hdrs,
66
-					  int flags,
67
-					  unsigned int cseq)
62
+bool AmSessionEventHandler::onSendRequest(AmSipRequest& req, int flags)
68 63
 {
69 64
   return false;
70 65
 }
... ...
@@ -71,13 +71,7 @@ public:
71 71
   virtual bool onSipReqTimeout(const AmSipRequest &);
72 72
   virtual bool onSipRplTimeout(const AmSipRequest &, const AmSipReply &);
73 73
 
74
-  virtual bool onSendRequest(const string& method, 
75
-			     const string& content_type,
76
-			     const string& body,
77
-			     string& hdrs,
78
-			     int flags,
79
-			     unsigned int cseq);
80
-
74
+  virtual bool onSendRequest(AmSipRequest& req, int flags);
81 75
   virtual bool onSendReply(AmSipReply& reply, int flags);
82 76
 };
83 77
 
... ...
@@ -59,38 +59,8 @@ const char* AmSipDialog::getStatusStr()
59 59
   return dlgStatusStr(status);
60 60
 }
61 61
 
62
-const char* __dlg_oa_status2str[AmSipDialog::__max_OA]  = {
63
-    "None",
64
-    "OfferRecved",
65
-    "OfferSent",
66
-    "Completed"
67
-};
68
-
69
-const char* getOAStatusStr(AmSipDialog::OAState st) {
70
-  if((st < 0) || (st >= AmSipDialog::__max_OA))
71
-    return "Invalid";
72
-  else
73
-    return __dlg_oa_status2str[st];
74
-}
75
-
76
-void AmSipDialog::OATrans::clear()
77
-{
78
-  state = OA_None;
79
-  cseq  = 0;
80
-  sdp_remote.clear();
81
-  sdp_local.clear();
82
-}
83
-
84
-void AmSipDialog::OATrans::clearTransitionalState()
85
-{
86
-  if(state != OA_Completed){
87
-    clear();
88
-  }
89
-}
90
-
91
-
92 62
 AmSipDialog::AmSipDialog(AmSipDialogEventHandler* h)
93
-  : status(Disconnected),oa_trans(),
63
+  : status(Disconnected),oa(this),
94 64
     early_session_started(false),session_started(false),
95 65
     cseq(10),r_cseq_i(false),hdl(h),
96 66
     pending_invites(0),cancel_pending(false),
... ...
@@ -137,16 +107,6 @@ void AmSipDialog::setStatus(Status new_status) {
137 107
   status = new_status;
138 108
 }
139 109
 
140
-AmSipDialog::OAState AmSipDialog::get_OA_state() {
141
-  return oa_trans.state;
142
-}
143
-
144
-void AmSipDialog::set_OA_state(OAState new_oa_state) {
145
-  DBG("setting SIP dialog O/A status: %s->%s\n",
146
-      getOAStatusStr(oa_trans.state), getOAStatusStr(new_oa_state));
147
-  oa_trans.state = new_oa_state;
148
-}
149
-
150 110
 void AmSipDialog::onRxRequest(const AmSipRequest& req)
151 111
 {
152 112
   DBG("AmSipDialog::onRxRequest(req = %s)\n", req.method.c_str());
... ...
@@ -171,7 +131,11 @@ void AmSipDialog::onRxRequest(const AmSipRequest& req)
171 131
     }
172 132
 
173 133
     if (req.method == SIP_METH_INVITE) {
174
-      if(pending_invites || ((oa_trans.state != OA_None) && (oa_trans.state != OA_Completed))) {      
134
+      if( pending_invites ||
135
+	  // not sure this is needed here: could be in AmOfferAnswer as well
136
+	  ((oa.getState() != AmOfferAnswer::OA_None) && 
137
+	   (oa.getState() != AmOfferAnswer::OA_Completed))) {
138
+
175 139
 	reply_error(req, 491, SIP_REPLY_PENDING,
176 140
 		    SIP_HDR_COLSP(SIP_HDR_RETRY_AFTER) + int2str(get_random() % 10) + CRLF,
177 141
 		    next_hop_for_replies ? next_hop_ip : "",
... ...
@@ -209,8 +173,6 @@ void AmSipDialog::onRxRequest(const AmSipRequest& req)
209 173
     }
210 174
   }
211 175
 
212
-  saveStates();
213
-
214 176
   switch(status){
215 177
   case Disconnected:
216 178
     if(req.method == SIP_METH_INVITE)
... ...
@@ -234,162 +196,19 @@ void AmSipDialog::onRxRequest(const AmSipRequest& req)
234 196
 
235 197
   default: break;
236 198
   }
237
-
238
-  const char* err_txt  = NULL;
239
-  int         err_code = 0;
240
-
241
-  if((req.method == SIP_METH_INVITE || 
242
-      req.method == SIP_METH_UPDATE || 
243
-      req.method == SIP_METH_ACK ||
244
-      req.method == SIP_METH_PRACK) &&
245
-     !req.body.empty() && 
246
-     (req.content_type == SIP_APPLICATION_SDP)) {
247
-
248
-    err_code = onRxSdp(req.cseq,req.body,&err_txt);
249
-  }
250
-
251
-  if(checkStateChange()){
252
-    err_code = 500;
253
-    err_txt = "internal error";
254
-  }
255
-
256
-  if(err_code){
257
-    if( req.method != SIP_METH_ACK ){ // INVITE || UPDATE || PRACK
258
-      reply(req,err_code,err_txt);
259
-    }
260
-    else { // ACK
261
-      // TODO: only if reply to initial INVITE (if re-INV, app should decide)
262
-      DBG("error %i with SDP received in ACK request: sending BYE\n",err_code);
263
-      bye();
264
-    }
265
-  }
266
-
267
-  if((req.method == SIP_METH_ACK) &&
268
-     (req.cseq == oa_trans.cseq)){
269
-    // 200 ACK received:
270
-    //  -> reset OA state
271
-    DBG("200 ACK received: resetting OA state");
272
-    oa_trans.clearTransitionalState();
273
-  }
199
+  
200
+  oa.onRequestIn(req);
274 201
 
275 202
   if(rel100OnRequestIn(req) && hdl)
276 203
     hdl->onSipRequest(req);
277 204
 }
278 205
 
279
-int AmSipDialog::onRxSdp(unsigned int m_cseq, const string& body, const char** err_txt)
280
-{
281
-  DBG("entering onRxSdp(), oa_state=%s\n", getOAStatusStr(oa_trans.state));
282
-  OAState old_oa_state = oa_trans.state;
283
-
284
-  int err_code = 0;
285
-  assert(err_txt);
286
-
287
-  if(oa_trans.sdp_remote.parse(body.c_str())){
288
-    err_code = 400;
289
-    *err_txt = "session description parsing failed";
290
-  }
291
-  else if(oa_trans.sdp_remote.media.empty()){
292
-    err_code = 400;
293
-    *err_txt = "no media line found in SDP message";
294
-  }
295
-
296
-  if(err_code == 0) {
297
-
298
-    switch(oa_trans.state) {
299
-    case OA_None:
300
-    case OA_Completed:
301
-      oa_trans.state = OA_OfferRecved;
302
-      oa_trans.cseq = m_cseq;
303
-      break;
304
-      
305
-    case OA_OfferSent:
306
-      oa_trans.state = OA_Completed;
307
-      break;
308
-
309
-    case OA_OfferRecved:
310
-      err_code = 400;// TODO: check correct error code
311
-      *err_txt = "pending SDP offer";
312
-      break;
313
-
314
-    default:
315
-      assert(0);
316
-      break;
317
-    }
318
-  }
319
-
320
-  if(err_code != 0) {
321
-    oa_trans.clear();
322
-  }
323
-
324
-  DBG("oa_state: %s -> %s\n", getOAStatusStr(old_oa_state), getOAStatusStr(oa_trans.state));
325
-
326
-  return err_code;
327
-}
328
-
329
-int AmSipDialog::onTxSdp(unsigned int m_cseq, const string& body)
330
-{
331
-  // assume that the payload is ok if it is not empty.
332
-  // (do not parse again self-generated SDP)
333
-  if(body.empty()){
334
-    return -1;
335
-  }
336
-
337
-  switch(oa_trans.state) {
338
-
339
-  case OA_None:
340
-  case OA_Completed:
341
-    oa_trans.state = OA_OfferSent;
342
-    oa_trans.cseq = m_cseq;
343
-    break;
344
-
345
-  case OA_OfferRecved:
346
-    oa_trans.state = OA_Completed;
347
-    break;
348
-
349
-  case OA_OfferSent:
350
-    // There is already a pending offer!!!
351
-    DBG("There is already a pending offer, onTxSdp fails\n");
352
-    return -1;
353
-
354
-  default:
355
-    break;
356
-  }
357
-
358
-  return 0;
359
-}
360
-
361 206
 int AmSipDialog::onSdpCompleted()
362 207
 {
363
-  if(oa_trans.state != OA_Completed)
364
-    return -1;
365
-
366
-  int ret = hdl->onSdpCompleted(oa_trans.sdp_local, oa_trans.sdp_remote);
208
+  int ret = hdl->onSdpCompleted(oa.getLocalSdp(), oa.getRemoteSdp());
367 209
   if(!ret) {
368
-    sdp_local = oa_trans.sdp_local;
369
-    sdp_remote = oa_trans.sdp_remote;
370
-  }
371
-  else {
372
-    oa_trans.state = OA_None;
373
-  }
374
-
375
-  return ret;
376
-}
377
-
378
-void AmSipDialog::saveStates()
379
-{
380
-  saved_status = status;
381
-  saved_oa_state = oa_trans.state;
382
-}
383
-
384
-int AmSipDialog::checkStateChange()
385
-{
386
-  int ret = 0;
387
-
388
-  if((saved_oa_state != oa_trans.state) &&
389
-     (oa_trans.state == OA_Completed)) {
390
-
391
-    ret = onSdpCompleted();
392
-    if(ret) return ret;
210
+    sdp_local = oa.getLocalSdp();
211
+    sdp_remote = oa.getRemoteSdp();
393 212
 
394 213
     if((getStatus() == Early) && !early_session_started) {
395 214
       hdl->onEarlySessionStart();
... ...
@@ -401,42 +220,21 @@ int AmSipDialog::checkStateChange()
401 220
       session_started = true;
402 221
     }
403 222
   }
223
+  else {
224
+    oa.clear();
225
+  }
404 226
 
405 227
   return ret;
406 228
 }
407 229
 
408
-int AmSipDialog::getSdpBody(string& sdp_body)
230
+bool AmSipDialog::getSdpOffer(AmSdp& offer)
409 231
 {
410
-    switch(oa_trans.state){
411
-    case OA_None:
412
-    case OA_Completed:
413
-      if(hdl->getSdpOffer(oa_trans.sdp_local)){
414
-	oa_trans.sdp_local.print(sdp_body);
415
-      }
416
-      else {
417
-	DBG("No SDP Offer.\n");
418
-	return -1;
419
-      }
420
-      break;
421
-    case OA_OfferRecved:
422
-      if(hdl->getSdpAnswer(oa_trans.sdp_remote,oa_trans.sdp_local)){
423
-	oa_trans.sdp_local.print(sdp_body);
424
-      }
425
-      else {
426
-	DBG("No SDP Answer.\n");
427
-	return -1;
428
-      }
429
-      break;
430
-      
431
-    case OA_OfferSent:
432
-      DBG("Still waiting for a reply\n");
433
-      return -1;
434
-
435
-    default: 
436
-      break;
437
-    }
232
+  return hdl->getSdpOffer(offer);
233
+}
438 234
 
439
-    return 0;
235
+bool AmSipDialog::getSdpAnswer(const AmSdp& offer, AmSdp& answer)
236
+{
237
+  return hdl->getSdpAnswer(offer,answer);
440 238
 }
441 239
 
442 240
 int AmSipDialog::rel100OnRequestIn(const AmSipRequest& req)
... ...
@@ -526,30 +324,6 @@ void AmSipDialog::initFromLocalRequest(const AmSipRequest& req)
526 324
 // (called from AmSipDialog::sendRequest())
527 325
 int AmSipDialog::onTxRequest(AmSipRequest& req)
528 326
 {
529
-  bool generate_sdp = req.body.empty() 
530
-    && (req.content_type == SIP_APPLICATION_SDP);
531
-
532
-  bool has_sdp = !req.body.empty() 
533
-    && (req.content_type == SIP_APPLICATION_SDP);
534
-
535
-  if (!generate_sdp && !has_sdp && 
536
-      ((req.method == SIP_METH_PRACK) ||
537
-       (req.method == SIP_METH_ACK))) {
538
-    generate_sdp = (oa_trans.state == OA_OfferRecved);
539
-  }
540
-
541
-  if (generate_sdp) {
542
-    if (!getSdpBody(req.body)){
543
-      req.content_type = SIP_APPLICATION_SDP;
544
-      has_sdp = true;
545
-    }
546
-  }
547
-
548
-  if(has_sdp && (onTxSdp(req.cseq,req.body) != 0)){
549
-    DBG("onTxSdp() failed\n");
550
-    return -1;
551
-  }
552
-
553 327
   if((req.method == SIP_METH_INVITE) && (status == Disconnected)){
554 328
     status = Trying;
555 329
   }
... ...
@@ -563,51 +337,6 @@ int AmSipDialog::onTxRequest(AmSipRequest& req)
563 337
 // UAS behavior for locally sent replies
564 338
 int AmSipDialog::onTxReply(AmSipReply& reply)
565 339
 {
566
-  bool generate_sdp = reply.body.empty() 
567
-    && (reply.content_type == SIP_APPLICATION_SDP);
568
-
569
-  bool has_sdp = !reply.body.empty() 
570
-    && (reply.content_type == SIP_APPLICATION_SDP);
571
-
572
-  if (!has_sdp && !generate_sdp) {
573
-    // let's see whether we should force SDP or not.
574
-
575
-    if (reply.cseq_method == SIP_METH_INVITE){
576
-      
577
-      if ((reply.code == 183) 
578
-	  || ((reply.code >= 200) && (reply.code < 300))) {
579
-	
580
-	// either offer received or no offer at all:
581
-	//  -> force SDP
582
-	generate_sdp = (oa_trans.state == OA_OfferRecved) 
583
-	  || (oa_trans.state == OA_None);
584
-      }
585
-    }
586
-    else if (reply.cseq_method == SIP_METH_UPDATE) {
587
-
588
-      if ((reply.code >= 200) &&
589
-	  (reply.code < 300)) {
590
-	
591
-	// offer received:
592
-	//  -> force SDP
593
-	generate_sdp = (oa_trans.state == OA_OfferRecved);
594
-      }
595
-    }
596
-  }
597
-  
598
-  if (generate_sdp) {
599
-    if(!getSdpBody(reply.body)) {
600
-      reply.content_type = SIP_APPLICATION_SDP;
601
-      has_sdp = true;
602
-    }
603
-  }
604
-
605
-  if (has_sdp && (onTxSdp(reply.cseq,reply.body) != 0)) {
606
-    
607
-    DBG("onTxSdp() failed\n");
608
-    return -1;
609
-  }
610
-
611 340
   // update Dialog status
612 341
   switch(status){
613 342
 
... ...
@@ -620,6 +349,7 @@ int AmSipDialog::onTxReply(AmSipReply& reply)
620 349
 	(reply.code < 200) ) {
621 350
       // refuse local provisional replies 
622 351
       // when state is Cancelling
352
+      ERROR("refuse local provisional replies when state is Cancelling\n");
623 353
       return -1;
624 354
     }
625 355
     // else continue with final
... ...
@@ -654,15 +384,6 @@ int AmSipDialog::onTxReply(AmSipReply& reply)
654 384
     break;
655 385
   }
656 386
 
657
-  if ((reply.code >= 200) && 
658
-      ((reply.cseq_method != "CANCEL"))) {
659
-    
660
-    if(reply.cseq_method == "INVITE") 
661
-      pending_invites--;
662
-    
663
-    uas_trans.erase(reply.cseq);
664
-  }
665
-    
666 387
   return 0;
667 388
 }
668 389
   
... ...
@@ -679,7 +400,8 @@ void AmSipDialog::onRxReply(const AmSipReply& reply)
679 400
       reply.code, reply.reason.c_str());
680 401
 
681 402
   string trans_method = t_it->second.method;
682
-  saveStates();
403
+
404
+  Status saved_status = status;
683 405
 
684 406
   // rfc3261 12.1
685 407
   // Dialog established only by 101-199 or 2xx 
... ...
@@ -775,37 +497,11 @@ void AmSipDialog::onRxReply(const AmSipReply& reply)
775 497
     }
776 498
   }
777 499
 
778
-  const char* err_txt  = NULL;
779
-  int         err_code = 0;
780
-
781
-  if((reply.cseq_method == SIP_METH_INVITE || 
782
-      reply.cseq_method == SIP_METH_UPDATE || 
783
-      reply.cseq_method == SIP_METH_PRACK) &&
784
-     !reply.body.empty() && 
785
-     (reply.content_type == SIP_APPLICATION_SDP)) {
786
-
787
-    if(((oa_trans.state == OA_Completed) ||
788
-	(oa_trans.state == OA_OfferRecved)) &&
789
-       (reply.cseq == oa_trans.cseq)) {
790
-      
791
-      DBG("ignoring subsequent SDP reply within the same transaction\n");
792
-      DBG("this usually happens when 183 and 200 have SDP\n");
793
-    }
794
-    else {
795
-      err_code = onRxSdp(reply.cseq,reply.body,&err_txt);
796
-    }
797
-  }
798
-
799
-  checkStateChange();
500
+  oa.onReplyIn(reply);
800 501
 
801
-  if(err_code){
802
-    // TODO: only if initial INVITE (if re-INV, app should decide)
803
-    DBG("error %i (%s) with SDP received in %i reply: sending ACK+BYE\n",
804
-	err_code,err_txt?err_txt:"none",reply.code);
805
-    bye();
806
-  }
502
+  if(rel100OnReplyIn(reply) && hdl)
503
+    hdl->onSipReply(reply, saved_status);
807 504
 
808
-  int cont = rel100OnReplyIn(reply);
809 505
   if(reply.code >= 200){
810 506
     if((reply.code < 300) && (trans_method == SIP_METH_INVITE)) {
811 507
 
... ...
@@ -819,23 +515,11 @@ void AmSipDialog::onRxReply(const AmSipReply& reply)
819 515
       // error reply or method != INVITE
820 516
       uac_trans.erase(t_it);
821 517
 
822
-      if(reply.cseq == oa_trans.cseq){
823
-	// transaction has been removed:
824
-	//  -> cleanup OA state
825
-	DBG("after %u reply to %s: resetting OA state\n",
826
-	    reply.code, trans_method.c_str());
827
-	oa_trans.clearTransitionalState();
828
-      }
829
-
830 518
       if ((reply.code == 408 || reply.code == 481) && (status == Connected)) {
831 519
 	hdl->onRemoteDisappeared(reply);
832 520
       }
833
-
834 521
     }
835 522
   }
836
-
837
-  if(cont && hdl)
838
-    hdl->onSipReply(reply, saved_status);
839 523
 }
840 524
 
841 525
 int AmSipDialog::rel100OnReplyIn(const AmSipReply &reply)
... ...
@@ -901,10 +585,7 @@ void AmSipDialog::uasTimeout(AmSipTimeoutEvent* to_ev)
901 585
   switch(to_ev->type){
902 586
   case AmSipTimeoutEvent::noACK:
903 587
     DBG("Timeout: missing ACK\n");
904
-    if(to_ev->cseq == oa_trans.cseq){
905
-      DBG("ACK timeout: resetting OA state\n");
906
-      oa_trans.clearTransitionalState();
907
-    }
588
+    oa.onNoAck(to_ev->cseq);
908 589
     if(hdl) hdl->onNoAck(to_ev->cseq);
909 590
     break;
910 591
 
... ...
@@ -1158,8 +839,6 @@ int AmSipDialog::reply(const AmSipTransaction& t,
1158 839
   reply.content_type = content_type;
1159 840
   reply.body = body;
1160 841
 
1161
-  rel100OnReplyOut(reply);
1162
-
1163 842
   if (!flags&SIP_FLAGS_VERBATIM) {
1164 843
     // add Signature
1165 844
     if (AmConfig::Signature.length())
... ...
@@ -1171,14 +850,15 @@ int AmSipDialog::reply(const AmSipTransaction& t,
1171 850
     reply.contact = getContactHdr();
1172 851
   }
1173 852
 
1174
-  saveStates();
853
+  oa.onReplyOut(reply);
854
+  rel100OnReplyOut(reply);
855
+  hdl->onSendReply(reply,flags);
856
+
1175 857
   if(onTxReply(reply)){
1176 858
     DBG("onTxReply failed\n");
1177 859
     return -1;
1178 860
   }
1179 861
 
1180
-  hdl->onSendReply(reply,flags);
1181
-
1182 862
   int ret = SipCtrlInterface::send(reply, next_hop_for_replies ? next_hop_ip : "",
1183 863
 				   next_hop_for_replies ? next_hop_port : 0,
1184 864
 				   out_intf_for_replies ? outbound_interface : -1 );
... ...
@@ -1191,18 +871,16 @@ int AmSipDialog::reply(const AmSipTransaction& t,
1191 871
     return ret;
1192 872
   }
1193 873
 
1194
-  ret = checkStateChange();
1195
-
1196
-  if((uas_trans.find(reply.cseq) == uas_trans.end()) &&
1197
-     (reply.cseq == oa_trans.cseq) &&
1198
-     (reply.cseq_method != SIP_METH_INVITE)){
1199
-    // transaction has been removed:
1200
-    //  -> cleanup OA state
1201
-    DBG("transaction finished by final reply %u: resetting OA state\n", reply.cseq);
1202
-    oa_trans.clearTransitionalState();
874
+  if ((reply.code >= 200) && 
875
+      (reply.cseq_method != SIP_METH_CANCEL)) {
876
+    
877
+    if(reply.cseq_method == SIP_METH_INVITE) 
878
+      pending_invites--;
879
+    
880
+    uas_trans.erase(reply.cseq);
1203 881
   }
1204
-  
1205
-  return ret;
882
+
883
+  return oa.onReplySent(reply);
1206 884
 }
1207 885
 
1208 886
 
... ...
@@ -1528,13 +1206,6 @@ int AmSipDialog::sendRequest(const string& method,
1528 1206
 			     unsigned int req_cseq)
1529 1207
 {
1530 1208
   string msg,ser_cmd;
1531
-  string m_hdrs = hdrs;
1532
-
1533
-  if(hdl)
1534
-    hdl->onSendRequest(method,content_type,body,m_hdrs,flags,req_cseq);
1535
-
1536
-  rel100OnRequestOut(method, m_hdrs);
1537
-
1538 1209
   AmSipRequest req;
1539 1210
 
1540 1211
   req.method = method;
... ...
@@ -1554,13 +1225,6 @@ int AmSipDialog::sendRequest(const string& method,
1554 1225
   if((method!=SIP_METH_BYE)&&(method!=SIP_METH_CANCEL))
1555 1226
     req.contact = getContactHdr();
1556 1227
     
1557
-  if(!m_hdrs.empty())
1558
-    req.hdrs = m_hdrs;
1559
-  
1560
-  // if((method == "INVITE") && reliable_1xx){
1561
-  //   req.hdrs += get_100rel_hdr(reliable_1xx);
1562
-  // }
1563
-
1564 1228
   if (!(flags&SIP_FLAGS_VERBATIM)) {
1565 1229
     // add Signature
1566 1230
     if (AmConfig::Signature.length())
... ...
@@ -1576,10 +1240,14 @@ int AmSipDialog::sendRequest(const string& method,
1576 1240
   req.body = body;
1577 1241
   DBG("req.body = '%s'\n", req.body.c_str());
1578 1242
 
1579
-  saveStates();
1580
-  if(onTxRequest(req))
1243
+  if(oa.onRequestOut(req))
1581 1244
     return -1;
1582 1245
 
1246
+  rel100OnRequestOut(req);
1247
+  if(hdl)
1248
+    hdl->onSendRequest(req,flags);
1249
+
1250
+  onTxRequest(req);
1583 1251
   if(SipCtrlInterface::send(req, next_hop_ip, next_hop_port,outbound_interface)) {
1584 1252
     ERROR("Could not send request: method=%s; call-id=%s; cseq=%i\n",
1585 1253
 	  req.method.c_str(),req.callid.c_str(),req.cseq);
... ...
@@ -1590,25 +1258,27 @@ int AmSipDialog::sendRequest(const string& method,
1590 1258
     uac_trans[req_cseq] = AmSipTransaction(method,req_cseq,req.tt);
1591 1259
   }
1592 1260
   else {
1261
+    // probably never executed, as send_200_ack is used instead of sendRequest
1262
+    // note: non-200 ACKs are sent from the transaction layer
1593 1263
     uac_trans.erase(req_cseq);
1594 1264
   }
1595 1265
 
1596
-  return checkStateChange();
1266
+  return oa.onRequestSent(req);
1597 1267
 }
1598 1268
 
1599
-void AmSipDialog::rel100OnRequestOut(const string &method, string &hdrs)
1269
+void AmSipDialog::rel100OnRequestOut(AmSipRequest& req)
1600 1270
 {
1601
-  if (reliable_1xx == REL100_IGNORED || method!=SIP_METH_INVITE) // && method!=SIP_METH_OPTIONS)
1271
+  if (reliable_1xx == REL100_IGNORED || req.method!=SIP_METH_INVITE) // && method!=SIP_METH_OPTIONS)
1602 1272
     return;
1603 1273
 
1604 1274
   switch(reliable_1xx) {
1605 1275
     case REL100_SUPPORTED:
1606
-      if (! key_in_list(getHeader(hdrs, SIP_HDR_REQUIRE), SIP_EXT_100REL))
1607
-        hdrs += SIP_HDR_COLSP(SIP_HDR_SUPPORTED) SIP_EXT_100REL CRLF;
1276
+      if (! key_in_list(getHeader(req.hdrs, SIP_HDR_REQUIRE), SIP_EXT_100REL))
1277
+        req.hdrs += SIP_HDR_COLSP(SIP_HDR_SUPPORTED) SIP_EXT_100REL CRLF;
1608 1278
       break;
1609 1279
     case REL100_REQUIRE:
1610
-      if (! key_in_list(getHeader(hdrs, SIP_HDR_REQUIRE), SIP_EXT_100REL))
1611
-        hdrs += SIP_HDR_COLSP(SIP_HDR_REQUIRE) SIP_EXT_100REL CRLF;
1280
+      if (! key_in_list(getHeader(req.hdrs, SIP_HDR_REQUIRE), SIP_EXT_100REL))
1281
+        req.hdrs += SIP_HDR_COLSP(SIP_HDR_REQUIRE) SIP_EXT_100REL CRLF;
1612 1282
       break;
1613 1283
     default:
1614 1284
       ERROR("BUG: unexpected reliability switch value of '%d'.\n",
... ...
@@ -1642,14 +1312,9 @@ int AmSipDialog::send_200_ack(unsigned int inv_cseq,
1642 1312
     return -1;
1643 1313
   }
1644 1314
 
1645
-  string m_hdrs = hdrs;
1646
-
1647
-  if(hdl)
1648
-    hdl->onSendRequest("ACK",content_type,body,m_hdrs,flags,inv_cseq);
1649
-
1650 1315
   AmSipRequest req;
1651 1316
 
1652
-  req.method = "ACK";
1317
+  req.method = SIP_METH_ACK;
1653 1318
   req.r_uri = remote_uri;
1654 1319
 
1655 1320
   req.from = SIP_HDR_COLSP(SIP_HDR_FROM) + local_party;
... ...
@@ -1664,9 +1329,6 @@ int AmSipDialog::send_200_ack(unsigned int inv_cseq,
1664 1329
   req.callid = callid;
1665 1330
   req.contact = getContactHdr();
1666 1331
     
1667
-  if(!m_hdrs.empty())
1668
-    req.hdrs = m_hdrs;
1669
-  
1670 1332
   if (!(flags&SIP_FLAGS_VERBATIM)) {
1671 1333
     // add Signature
1672 1334
     if (AmConfig::Signature.length())
... ...
@@ -1680,25 +1342,18 @@ int AmSipDialog::send_200_ack(unsigned int inv_cseq,
1680 1342
   req.content_type = content_type;
1681 1343
   req.body = body;
1682 1344
   
1683
-  saveStates();
1684
-  if(onTxRequest(req))
1345
+  if(oa.onRequestOut(req))
1685 1346
     return -1;
1686 1347
 
1348
+  if(hdl)
1349
+    hdl->onSendRequest(req,flags);
1350
+
1351
+  //onTxRequest(req); // not needed right now in the ACK case
1687 1352
   if (SipCtrlInterface::send(req, next_hop_ip, next_hop_port, outbound_interface))
1688 1353
     return -1;
1689 1354
 
1690 1355
   uac_trans.erase(inv_cseq);
1691
-
1692
-  int ret = checkStateChange();
1693
-
1694
-  if(inv_cseq == oa_trans.cseq){
1695
-    // transaction has been removed:
1696
-    //  -> cleanup OA state
1697
-    DBG("200 ACK sent: resetting OA state\n");
1698
-    oa_trans.clearTransitionalState();
1699
-  }
1700
-
1701
-  return ret;
1356
+  return oa.onRequestSent(req);
1702 1357
 }
1703 1358
 
1704 1359
 
... ...
@@ -30,6 +30,7 @@
30 30
 
31 31
 #include "AmSipMsg.h"
32 32
 #include "AmSdp.h"
33
+#include "AmOfferAnswer.h"
33 34
 
34 35
 #include <string>
35 36
 #include <vector>
... ...
@@ -86,31 +87,6 @@ class AmSipDialog
86 87
     __max_Status
87 88
   };
88 89
 
89
-  enum OAState {
90
-    OA_None=0,
91
-    OA_OfferRecved,
92
-    OA_OfferSent,
93
-    OA_Completed,
94
-    __max_OA
95
-  };
96
-
97
-  struct OATrans {
98
-    OAState      state;
99
-    unsigned int cseq;
100
-    AmSdp        sdp_remote;
101
-    AmSdp        sdp_local;
102
-
103
-    OATrans()
104
-      : state(OA_None), 
105
-	cseq(0),
106
-	sdp_remote(),
107
-	sdp_local()
108
-    {};
109
-
110
-    void clear();
111
-    void clearTransitionalState();
112
-  };
113
-
114 90
   /** enable the reliability of provisional replies? */
115 91
   enum Rel100State {
116 92
     REL100_DISABLED=0,
... ...
@@ -139,15 +115,9 @@ private:
139 115
   // while in 'Trying' state
140 116
   bool         cancel_pending;
141 117
 
142
-  // Current offer/answer transaction
143
-  OATrans oa_trans;
144
-
145 118
   AmSdp   sdp_local;
146 119
   AmSdp   sdp_remote;
147 120
 
148
-  Status  saved_status;
149
-  OAState saved_oa_state;
150
-
151 121
   bool early_session_started;
152 122
   bool session_started;
153 123
 
... ...
@@ -156,26 +126,13 @@ private:
156 126
   int onTxReply(AmSipReply& reply);
157 127
   int onTxRequest(AmSipRequest& req);
158 128
 
159
-  int onRxSdp(unsigned int m_cseq, const string& body, const char** err_txt);
160
-  int onTxSdp(unsigned int m_cseq, const string& body);
161
-  int onSdpCompleted();
162
-
163
-  // Allows for saving dlg & OA states
164
-  void saveStates();
165
-  // Checks dlg & OA states against saved state
166
-  // and take appropriate action 
167
-  // (onSdpCompleted and/or onSessionStart/onEarlySessionStart)
168
-  int checkStateChange();
169
-
170
-  int getSdpBody(string& sdp_body);
171
-
172 129
   string getRoute();
173 130
 
174
-  int rel100OnRequestIn(const AmSipRequest &req);
175
-  int rel100OnReplyIn(const AmSipReply &reply);
176
-  void rel100OnTimeout(const AmSipRequest &req, const AmSipReply &rpl);
131
+  int rel100OnRequestIn(const AmSipRequest& req);
132
+  int rel100OnReplyIn(const AmSipReply& reply);
133
+  void rel100OnTimeout(const AmSipRequest& req, const AmSipReply& rpl);
177 134
 
178
-  void rel100OnRequestOut(const string &method, string &hdrs);
135
+  void rel100OnRequestOut(AmSipRequest& req);
179 136
   void rel100OnReplyOut(AmSipReply& reply);
180 137
 
181 138
   /** @return 0 on success */
... ...
@@ -225,6 +182,9 @@ private:
225 182
   bool r_cseq_i;
226 183
   unsigned int r_cseq; // last remote CSeq  
227 184
 
185
+  // Current offer/answer transaction
186
+  AmOfferAnswer oa;
187
+
228 188
   AmSipDialog(AmSipDialogEventHandler* h);
229 189
   ~AmSipDialog();
230 190
 
... ...
@@ -248,13 +208,10 @@ private:
248 208
 
249 209
   void   setStatus(Status new_status);
250 210
 
251
-  /** get offer/answer state */
252
-  OAState get_OA_state();
253
-  /** set offer/answer state (handle with caution!) */
254
-  void set_OA_state(OAState new_oa_state);
255
-
256 211
   string getContactHdr();
257 212
 
213
+  AmSipDialogEventHandler* getDialogEventHandler() { return hdl; }
214
+
258 215
   /** 
259 216
    * Computes, set and return the outbound interface
260 217
    * based on remote_uri, next_hop_ip, outbound_proxy, route.
... ...
@@ -273,6 +230,15 @@ private:
273 230
   void onRxRequest(const AmSipRequest& req);
274 231
   void onRxReply(const AmSipReply& reply);
275 232
 
233
+  /** 
234
+   * Calls onSdpCompleted on the session event handler
235
+   * and executes onSessionStart/onEarlySessionStart when required.
236
+   */
237
+  int onSdpCompleted();
238
+
239
+  bool getSdpOffer(AmSdp& offer);
240
+  bool getSdpAnswer(const AmSdp& offer, AmSdp& answer);
241
+
276 242
   void uasTimeout(AmSipTimeoutEvent* to_ev);
277 243
     
278 244
   /** @return 0 on success (deprecated) */
... ...
@@ -377,12 +343,7 @@ class AmSipDialogEventHandler
377 343
 			  AmSipDialog::Status old_dlg_status)=0;
378 344
 
379 345
   /** Hook called before a request is sent */
380
-  virtual void onSendRequest(const string& method,
381
-			     const string& content_type,
382
-			     const string& body,
383
-			     string& hdrs,
384
-			     int flags,
385
-			     unsigned int req_cseq)=0;
346
+  virtual void onSendRequest(AmSipRequest& req, int flags)=0;