Browse code

fix session leak on 100rel disabled

In case 100rel is disabled on SEMS' side, but UAC requires it, SEMS
would reject the INVITE, drop further processing on the session, but
still keep it. If INVITE is first in session, UAC would clear the
dialog, but SEMS would still keep it.

But spotted and explained by Stefan S.

bpintea authored on 07/03/2011 00:51:06
Showing 4 changed files
... ...
@@ -1216,16 +1216,23 @@ void AmSession::onFailure(AmSipDialogEventHandler::FailureCause cause,
1216 1216
     const AmSipRequest *req, const AmSipReply *rpl)
1217 1217
 {
1218 1218
   switch (cause) {
1219
-    case FAIL_REL100:
1219
+    case FAIL_REL100_421:
1220
+    case FAIL_REL100_420:
1220 1221
       if (rpl) {
1221 1222
         dlg.cancel();
1222 1223
         if (dlg.getStatus() < AmSipDialog::Connected)
1223 1224
           setStopped();
1224 1225
       } else if (req) {
1225
-          dlg.reply(*req, 421, "Extension Required", "", "",
1226
+        if (cause == FAIL_REL100_421) {
1227
+          dlg.reply(*req, 421, SIP_REPLY_EXTENSION_REQUIRED, "", "",
1226 1228
               SIP_HDR_COLSP(SIP_HDR_REQUIRE) SIP_EXT_100REL CRLF);
1227
-          if (dlg.getStatus() < AmSipDialog::Connected)
1228
-            setStopped();
1229
+        } else {
1230
+          dlg.reply(*req, 420, SIP_REPLY_BAD_EXTENSION, "", "",
1231
+              SIP_HDR_COLSP(SIP_HDR_UNSUPPORTED) SIP_EXT_100REL CRLF);
1232
+        }
1233
+        /* finally, stop session if running */
1234
+        if (dlg.getStatus() < AmSipDialog::Connected)
1235
+          setStopped();
1229 1236
       }
1230 1237
       break;
1231 1238
     default:
... ...
@@ -173,19 +173,17 @@ int AmSipDialog::rel100OnRequestIn(const AmSipRequest& req)
173 173
               SIP_EXT_100REL))) {
174 174
           ERROR("'" SIP_EXT_100REL "' extension required, but not advertised"
175 175
             " by peer.\n");
176
-          if (hdl) hdl->onFailure(FAIL_REL100, &req, 0);
176
+          if (hdl) hdl->onFailure(FAIL_REL100_421, &req, 0);
177 177
           return 0; // has been replied
178 178
         }
179 179
         break; // 100rel required
180 180
 
181 181
       case REL100_DISABLED:
182 182
         // TODO: shouldn't this be part of a more general check in SEMS?
183
-        if (key_in_list(getHeader(req.hdrs,SIP_HDR_REQUIRE),SIP_EXT_100REL))
184
-          reply_error(req, 420, SIP_REPLY_BAD_EXTENSION, 
185
-		      SIP_HDR_COLSP(SIP_HDR_UNSUPPORTED) SIP_EXT_100REL CRLF,
186
-		      next_hop_for_replies ? next_hop_ip : "",
187
-		      next_hop_for_replies ? next_hop_port : 0);
188
-	return 0;
183
+        if (key_in_list(getHeader(req.hdrs,SIP_HDR_REQUIRE),SIP_EXT_100REL)) {
184
+          if (hdl) hdl->onFailure(FAIL_REL100_420, &req, 0);
185
+          return 0; // has been replied
186
+        }
189 187
         break;
190 188
 
191 189
       default:
... ...
@@ -416,7 +414,7 @@ int AmSipDialog::rel100OnReplyIn(const AmSipReply &reply)
416 416
           !reply.rseq) {
417 417
         ERROR(SIP_EXT_100REL " not supported or no positive RSeq value in "
418 418
             "(reliable) 1xx.\n");
419
-        if (hdl) hdl->onFailure(FAIL_REL100, 0, &reply);
419
+        if (hdl) hdl->onFailure(FAIL_REL100_421, 0, &reply);
420 420
       } else {
421 421
         DBG(SIP_EXT_100REL " now active.\n");
422 422
         if (hdl) hdl->onInvite1xxRel(reply);
... ...
@@ -436,7 +434,7 @@ int AmSipDialog::rel100OnReplyIn(const AmSipReply &reply)
436 436
   } else if (reliable_1xx && reply.method==SIP_METH_PRACK) {
437 437
     if (300 <= reply.code) {
438 438
       // if PRACK fails, tear down session
439
-      if (hdl) hdl->onFailure(FAIL_REL100, 0, &reply);
439
+      if (hdl) hdl->onFailure(FAIL_REL100_421, 0, &reply);
440 440
     } else if (200 <= reply.code) {
441 441
       if (hdl) hdl->onPrack2xx(reply);
442 442
     } else {
... ...
@@ -110,8 +110,10 @@ class AmSipDialogEventHandler
110 110
   virtual void onPrack2xx(const AmSipReply &)=0;
111 111
 
112 112
   enum FailureCause {
113
-    FAIL_REL100,
114
-#define FAIL_REL100  AmSipDialogEventHandler::FAIL_REL100
113
+    FAIL_REL100_421,
114
+#define FAIL_REL100_421  AmSipDialogEventHandler::FAIL_REL100_421
115
+    FAIL_REL100_420,
116
+#define FAIL_REL100_420  AmSipDialogEventHandler::FAIL_REL100_420
115 117
   };
116 118
   virtual void onFailure(FailureCause cause, const AmSipRequest*, 
117 119
       const AmSipReply*)=0;
... ...
@@ -52,4 +52,5 @@
52 52
 
53 53
 #define SIP_REPLY_SERVER_INTERNAL_ERROR "Server Internal Error"
54 54
 #define SIP_REPLY_BAD_EXTENSION         "Bad Extension"
55
+#define SIP_REPLY_EXTENSION_REQUIRED    "Extension Required"
55 56
 #endif /* __AMSIPHEADERS_H__ */