Browse code

properly evaluate minimum session timer

fixes bug #42 (https://bugtracker.iptel.org/view.php?id=42)

422 Session Interval Too Small is replied with the configured
min-se value, if session refresh interval is too low.

Stefan Sayer authored on 23/08/2010 17:17:12
Showing 11 changed files
... ...
@@ -69,6 +69,8 @@ int SSTB2BFactory::onLoad()
69 69
 
70 70
 AmSession* SSTB2BFactory::onInvite(const AmSipRequest& req)
71 71
 {
72
+  if (!session_timer_fact->onInvite(req, cfg))
73
+    return NULL;
72 74
 
73 75
   SSTB2BDialog* b2b_dlg = new SSTB2BDialog();
74 76
   AmSessionEventHandler* h = session_timer_fact->getHandler(b2b_dlg);
... ...
@@ -76,6 +78,7 @@ AmSession* SSTB2BFactory::onInvite(const AmSipRequest& req)
76 78
     ERROR("could not get a session timer event handler\n");
77 79
     throw AmSession::Exception(500,"Server internal error");
78 80
   }
81
+
79 82
   if(h->configure(cfg)){
80 83
     ERROR("Could not configure the session timer: disabling session timers.\n");
81 84
     delete h;
... ...
@@ -94,9 +94,10 @@ AmSessionEventHandlerFactory::AmSessionEventHandlerFactory(const string& name)
94 94
 }
95 95
 
96 96
 bool AmSessionEventHandlerFactory::onInvite(const AmSipRequest& req, 
97
-						  AmArg& session_params) {
97
+					    AmArg& session_params,
98
+					    AmConfigReader& cfg) {
98 99
   WARN("discarding session parameters for new session.\n");
99
-  return onInvite(req);
100
+  return onInvite(req, cfg);
100 101
 }
101 102
 
102 103
 // AmSIPEventHandler::AmSIPEventHandler(const string& name) 
... ...
@@ -110,10 +110,10 @@ class AmSessionEventHandlerFactory: public AmPluginFactory
110 110
   virtual AmSessionEventHandler* getHandler(AmSession*)=0;
111 111
 
112 112
   /**
113
-   * @return true if session creation should be stopped
113
+   * @return false if session creation should be stopped
114 114
    */
115
-  virtual bool onInvite(const AmSipRequest& req)=0;
116
-  virtual bool onInvite(const AmSipRequest& req, AmArg& session_params);
115
+  virtual bool onInvite(const AmSipRequest& req, AmConfigReader& cfg)=0;
116
+  virtual bool onInvite(const AmSipRequest& req, AmArg& session_params, AmConfigReader& cfg);
117 117
 };
118 118
 
119 119
 /** \brief Interface for plugins to create sessions */
... ...
@@ -195,7 +195,8 @@ public:
195 195
   struct Exception {
196 196
     int code;
197 197
     string reason;
198
-    Exception(int c, string r) : code(c), reason(r) {}
198
+    string hdrs;
199
+    Exception(int c, string r, string h="") : code(c), reason(r), hdrs(h) {}
199 200
   };
200 201
 
201 202
   /** 
... ...
@@ -307,8 +307,8 @@ void AmSessionContainer::startSessionUAS(AmSipRequest& req)
307 307
       }
308 308
   } 
309 309
   catch(const AmSession::Exception& e){
310
-    ERROR("%i %s\n",e.code,e.reason.c_str());
311
-    AmSipDialog::reply_error(req,e.code,e.reason);
310
+    ERROR("%i %s %s\n",e.code,e.reason.c_str(), e.hdrs.c_str());
311
+    AmSipDialog::reply_error(req,e.code,e.reason, e.hdrs);
312 312
   }
313 313
   catch(const string& err){
314 314
     ERROR("startSession: %s\n",err.c_str());
... ...
@@ -76,10 +76,18 @@ int EchoFactory::onLoad()
76 76
 
77 77
 AmSession* EchoFactory::onInvite(const AmSipRequest& req)
78 78
 {
79
+  if (NULL != session_timer_f) {
80
+    if (!session_timer_f->onInvite(req, conf))
81
+      return NULL;
82
+  }
83
+
79 84
   AmSession* s = new EchoDialog();
80 85
   
81 86
   if (NULL != session_timer_f) {
87
+
82 88
     AmSessionEventHandler* h = session_timer_f->getHandler(s);
89
+    if (NULL == h)
90
+      return NULL;
83 91
     
84 92
     if(h->configure(conf)){
85 93
       ERROR("Could not configure the session timer: disabling session timers.\n");
... ...
@@ -37,11 +37,9 @@ int SessionTimerFactory::onLoad()
37 37
   return 0;
38 38
 }
39 39
 
40
-bool SessionTimerFactory::onInvite(const AmSipRequest& req)
40
+bool SessionTimerFactory::onInvite(const AmSipRequest& req, AmConfigReader& cfg)
41 41
 {
42
-  if(!checkSessionExpires(req))
43
-    return true;
44
-  return false;
42
+  return checkSessionExpires(req, cfg);
45 43
 }
46 44
 
47 45
 
... ...
@@ -127,11 +125,9 @@ bool SessionTimer::onSendReply(const AmSipRequest& req,
127 125
   return false;
128 126
 }
129 127
 
130
-
131
-/* Session Timer: -ssa */
132
-int  SessionTimer::configure(AmConfigReader& conf) 
128
+int SessionTimer::configure(AmConfigReader& conf)
133 129
 {
134
-  if(session_timer_conf.readFromConfig(conf))
130
+  if(!session_timer_conf.readFromConfig(conf))
135 131
     return -1;
136 132
 
137 133
   session_interval = session_timer_conf.getSessionExpires();
... ...
@@ -152,22 +148,29 @@ int  SessionTimer::configure(AmConfigReader& conf)
152 148
  *   (<locally configured Min-SE)                  
153 149
  * Throws SessionIntervalTooSmallException if too low
154 150
  */
155
-bool SessionTimerFactory::checkSessionExpires(const AmSipRequest& req) 
151
+bool SessionTimerFactory::checkSessionExpires(const AmSipRequest& req, AmConfigReader& cfg)
156 152
 {
153
+  AmSessionTimerConfig sst_cfg;
154
+  if (sst_cfg.readFromConfig(cfg)) {
155
+    return false;
156
+  }
157
+
157 158
   string session_expires = getHeader(req.hdrs, SIP_HDR_SESSION_EXPIRES,
158 159
 				     SIP_HDR_SESSION_EXPIRES_COMPACT, true);
159 160
 
160 161
   if (session_expires.length()) {
161 162
     unsigned int i_se;
162 163
     if (!str2i(strip_header_params(session_expires), i_se)) {
163
-
164
-      //if (i_se < session_timer_conf.getMinimumTimer()) {
165
-      //TODO: reply 422...
166
-      //}
167
-    } else
168
-      throw AmSession::Exception(500,"internal error"); // malformed request?
164
+      if (i_se < sst_cfg.getMinimumTimer()) {
165
+	throw AmSession::Exception(422, "Session Interval Too Small",
166
+				   SIP_HDR_COLSP(SIP_HDR_MIN_SE)+
167
+				   int2str(sst_cfg.getMinimumTimer())+CRLF);
168
+      }
169
+    } else {
170
+      WARN("parsing session expires '%s' failed\n", session_expires.c_str());
171
+      throw AmSession::Exception(400,"Bad Request");
172
+    }
169 173
   }
170
-  //}
171 174
 
172 175
   return true;
173 176
 }
... ...
@@ -49,20 +49,20 @@ class AmTimeoutEvent;
49 49
 /** \brief Factory of the session timer event handler */
50 50
 class SessionTimerFactory: public AmSessionEventHandlerFactory
51 51
 {
52
-  bool checkSessionExpires(const AmSipRequest& req);
52
+  bool checkSessionExpires(const AmSipRequest& req, AmConfigReader& cfg);
53 53
 
54 54
  public:
55 55
   SessionTimerFactory(const string& name)
56 56
     : AmSessionEventHandlerFactory(name) {}
57 57
 
58 58
   int onLoad();
59
-  bool onInvite(const AmSipRequest&);
59
+  bool onInvite(const AmSipRequest& req, AmConfigReader& cfg);
60 60
 
61 61
   AmSessionEventHandler* getHandler(AmSession* s);
62 62
 };
63 63
 
64 64
 /** \brief config for the session timer */
65
-class AmSessionTimerConfig 
65
+class AmSessionTimerConfig
66 66
 {
67 67
 
68 68
   /** Session Timer: enable? */
... ...
@@ -74,9 +74,9 @@ int UACAuthFactory::onLoad()
74 74
   return 0;
75 75
 }
76 76
 
77
-bool UACAuthFactory::onInvite(const AmSipRequest& req)
77
+bool UACAuthFactory::onInvite(const AmSipRequest& req, AmConfigReader& conf)
78 78
 {
79
-  return false;
79
+  return true;
80 80
 }
81 81
 
82 82
 AmSessionEventHandler* UACAuthFactory::getHandler(AmSession* s)
... ...
@@ -72,7 +72,7 @@ class UACAuthFactory
72 72
 
73 73
   // SessionEventHandler API
74 74
   AmSessionEventHandler* getHandler(AmSession* s);
75
-  bool onInvite(const AmSipRequest&);
75
+  bool onInvite(const AmSipRequest& req, AmConfigReader& conf);
76 76
 
77 77
   static UACAuthFactory* instance();
78 78
   AmDynInvoke* getInstance() { return instance(); }
... ...
@@ -12,3 +12,6 @@ star key pressed on the phone switches between adaptive playout
12 12
 buffer and fifo playout buffer. Thus the effect of the adaptive 
13 13
 playout buffering can easily be verified.
14 14
 
15
+The echo application is also a test application for RFC4028 SIP
16
+Session Timers. For this, enable_session_timer=yes needs to be
17
+set in echo.conf