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
AmBasicSipDialog(AmBasicSipEventHandler * h)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 #include "AmUriParser.h"
32 
33 #include <string>
34 #include <vector>
35 #include <map>
36 using std::string;
37 
38 // flags which may be used when sending request/reply
39 #define SIP_FLAGS_VERBATIM     1 // send request verbatim,
40                                  // i.e. modify as little as possible
~AmBasicSipDialog()41 
42 #define SIP_FLAGS_NOAUTH       1<<1 // don't add authentication header
43 #define SIP_FLAGS_NOCONTACT    1<<2 // don't add contact
44 
45 #define SIP_FLAGS_NOTAG        1<<3 // don't add to-tag in reply
46 
47 #define SIP_FLAGS_NOBL         1<<4 // do not use destination blacklist
48 
49 /** \brief SIP transaction representation */
50 struct AmSipTransaction
51 {
52   string       method;
53   unsigned int cseq;
54   trans_ticket tt;
55 
56   AmSipTransaction(const string& method, unsigned int cseq, const trans_ticket& tt)
57   : method(method),
58     cseq(cseq),
59     tt(tt)
60   {}
61 
62   AmSipTransaction()
63   {}
64 };
65 
66 typedef std::map<int,AmSipRequest> TransMap;
getUACTransMethod(unsigned int t_cseq)67 
68 class AmBasicSipEventHandler;
69 
70 class msg_logger;
71 
72 class AmBasicSipDialog
73   : public AmObject
74 {
75 public:
getUACTransPending()76   enum Status {
77     Disconnected=0,
78     Trying,
79     Proceeding,
80     Cancelling,
81     Early,
82     Connected,
83     Disconnecting,
84     __max_Status
85   };
86 
87 private:
88   static const char* status2str[__max_Status];
getStatusStr(AmBasicSipDialog::Status st)89 
90 protected:
91   Status status;
92 
93   string callid;
94 
95   string local_tag;
96   string ext_local_tag;
getStatusStr()97 
98   string remote_tag;
99   string first_branch;
100 
101   string contact_params; // params in Contact-HF
getContactHdr()102   AmUriParser contact;
103 
104   string user;         // local user
105   string domain;       // local domain
106 
107   string local_uri;    // local uri
108   string remote_uri;   // remote uri
109 
110   string remote_party; // To/From
111   string local_party;  // To/From
112 
113   string remote_ua; // User-Agent/Server
114 
115   string route;
116 
117   string next_hop;
118   bool next_hop_1st_req;
119   bool patch_ruri_next_hop;
120   bool next_hop_fixed;
121 
122   int outbound_interface;
123 
124   TransMap uas_trans;
125   TransMap uac_trans;
getContactUri()126 
127   /** Dialog usages in the sense of RFC 5057 */
128   unsigned int usages;
129 
130   AmBasicSipEventHandler* hdl;
131 
132   /**
133    * Message logger
134    */
135   msg_logger* logger;
136 
137   /**
138    * Executed for replies sent by a local UA,
139    * right before the reply is passed to the transaction layer.
140    */
141   virtual int onTxReply(const AmSipRequest& req, AmSipReply& reply, int& flags);
142 
143   /**
144    * Executed for requests sent by a local UA,
145    * right before the request is passed to the transaction layer.
146    */
147   virtual int onTxRequest(AmSipRequest& req, int& flags);
getRoute()148 
149   /**
150    * Executed for replies sent by a local UA,
151    * after the reply has been successfuly sent.
152    */
153   virtual void onReplyTxed(const AmSipRequest& req, const AmSipReply& reply);
154 
155   /**
156    * Executed for requests sent by a local UA,
157    * after the request has been successfuly sent.
158    */
159   virtual void onRequestTxed(const AmSipRequest& req);
160 
161   /**
162    * Basic sanity check on received requests
163    *
164    * Note: At this point in the processing,
165    *       the request has not been inserted yet
166    *       into the uas_trans container.
167    *       Thus, reply_error() should be used
168    *       instead of reply() method.
setOutboundInterface(int interface_id)169    *
170    * @return true to continue processing, false otherwise
171    */
172   virtual bool onRxReqSanity(const AmSipRequest& req);
173 
174   /**
175    * Executed from onRxRequest() to allow inherited classes
176    * to extend the basic behavior.
177    *
getOutboundIf()178    * @return true to continue processing, false otherwise
179    */
180   virtual bool onRxReqStatus(const AmSipRequest& req) { return true; }
181 
182   /**
183    * Basic sanity check on received replies
184    *
185    * @return true to continue processing, false otherwise
186    */
187   virtual bool onRxReplySanity(const AmSipReply& reply);
188 
189   /**
190    * Executed from onRxReply() to allow inherited classes
191    * to extend the basic behavior (deletes the transaction on final reply).
192    *
193    * @return true to continue processing, false otherwise
194    */
195   virtual bool onRxReplyStatus(const AmSipReply& reply);
196 
197   /**
198    * Terminate pending UAS transactions
199    */
200   virtual void termUasTrans();
201 
202   /**
203    * Terminate pending UAC transactions
204    */
205   virtual void termUacTrans();
206 
207 public:
208 
209   string outbound_proxy;
210   bool   force_outbound_proxy;
211 
212   bool nat_handling;
213 
214   unsigned int cseq; // Local CSeq for next request
215   bool r_cseq_i;
216   unsigned int r_cseq; // last remote CSeq
217 
218   AmBasicSipDialog(AmBasicSipEventHandler* h=NULL);
219   virtual ~AmBasicSipDialog();
220 
221   void setEventhandler(AmBasicSipEventHandler* h) { hdl = h; }
222 
223   /** @return UAC request coresponding to cseq or NULL */
224   AmSipRequest* getUACTrans(unsigned int t_cseq);
225 
226   /** @return UAS request coresponding to cseq or NULL */
227   AmSipRequest* getUASTrans(unsigned int t_cseq);
228 
229   /** @return the method of the corresponding uac request */
230   string getUACTransMethod(unsigned int t_cseq);
231 
232   /** @return whether UAC transaction is pending */
233   bool   getUACTransPending();
234 
235   /**
236    * Getter/Setter basic dialog status
237    */
238   Status       getStatus() const { return status; }
239   virtual void setStatus(Status new_status);
240 
241   virtual const char* getStatusStr();
242   static const char* getStatusStr(Status st);
243 
244   unsigned int getUsages() { return usages; }
245   void incUsages() { usages++; }
246   void decUsages() { usages--; }
247 
248   const string& getCallid() const { return callid; }
249   virtual void setCallid(const string& n_callid) { callid = n_callid; }
250 
251   const string& getLocalTag() const { return local_tag; }
252   virtual void setLocalTag(const string& n_tag) { local_tag = n_tag; }
253 
254   const string& getRemoteTag() const { return remote_tag; }
255   virtual void setRemoteTag(const string& n_tag);
256 
257   const string& get1stBranch() const { return first_branch; }
258   virtual void set1stBranch(const string& n_branch)
259   { first_branch = n_branch; }
260 
261   const string& getExtLocalTag() const { return ext_local_tag; }
262   virtual void setExtLocalTag(const string& new_ext_tag)
resetOutboundIf()263   { ext_local_tag = new_ext_tag; }
264 
265   const string& getContactParams() const { return contact_params; }
266   virtual void setContactParams(const string& new_contact_params)
267   { contact_params = new_contact_params; }
268 
269   const AmUriParser &getContact() const { return contact; }
270   virtual void setContact(const AmUriParser &new_contact)
initFromLocalRequest(const AmSipRequest & req)271   { contact = new_contact; }
272 
273   const string& getUser() const { return user; }
274   virtual void setUser(const string& new_user)
275   { user = new_user; }
276 
277   const string& getDomain() const { return domain; }
278   virtual void setDomain(const string& new_domain)
279   { domain = new_domain; }
280 
281   const string& getLocalUri() const { return local_uri; }
282   virtual void setLocalUri(const string& new_local_uri)
283   { local_uri = new_local_uri; }
284 
onRxReqSanity(const AmSipRequest & req)285   const string& getRemoteUri() const { return remote_uri; }
286   virtual void setRemoteUri(const string& new_remote_uri)
287   { remote_uri = new_remote_uri; }
288 
289   const string& getLocalParty() const { return local_party; }
290   virtual void setLocalParty(const string& new_local_party)
291   { local_party = new_local_party; }
292 
293   const string& getRemoteParty() const { return remote_party; }
294   virtual void setRemoteParty(const string& new_remote_party)
295   { remote_party = new_remote_party; }
296 
297   const string& getRemoteUA() const { return remote_ua; }
298   virtual void setRemoteUA(const string& new_remote_ua)
299   { remote_ua = new_remote_ua; }
300 
301   const string& getRouteSet() const { return route; }
302   virtual void setRouteSet(const string& new_rs)
303   { route = new_rs; }
304 
305   const string& getNextHop() const { return next_hop; }
306   virtual void setNextHop(const string& new_nh)
307   { next_hop = new_nh; }
308 
309   bool getNextHop1stReq() const { return next_hop_1st_req; }
310   virtual void setNextHop1stReq(bool nh_1st_req)
311   { next_hop_1st_req = nh_1st_req; }
312 
313   bool getPatchRURINextHop() const { return patch_ruri_next_hop; }
314   virtual void setPatchRURINextHop(bool patch_nh)
315   { patch_ruri_next_hop = patch_nh; }
316 
317   bool getNextHopFixed() const { return next_hop_fixed; }
318   virtual void setNextHopFixed(bool nh_fixed)
319   { next_hop_fixed = nh_fixed; }
320 
321   /**
322    * Compute the Contact-HF for the next request
323    */
onRxRequest(const AmSipRequest & req)324   string getContactHdr();
325 
326   /**
327    * Compute the Contact URI for the next request
328    */
329   string getContactUri();
330 
331   /**
332    * Compute the Route-HF for the next request
333    */
334   string getRoute();
335 
336   /**
337    * Set outbound_interface to specific value (-1 = default).
338    */
339   virtual void setOutboundInterface(int interface_id);
340 
341   /**
342    * Compute, set and return the outbound interface
343    * based on remote_uri, next_hop_ip, outbound_proxy, route.
344    */
345   int getOutboundIf();
346 
347   /**
348    * Reset outbound_interface to default value (-1).
349    */
350   void resetOutboundIf();
351 
352   /**
353    * Set outbound_interface to specific value (-1 = default).
354    */
355   //void setOutboundInterface(int interface_id);
356 
357   /** Initialize dialog from locally originated UAC request */
358   virtual void initFromLocalRequest(const AmSipRequest& req);
359 
360   /**
361    * Executed for requests received by the local UA.
362    */
363   virtual void onRxRequest(const AmSipRequest& req);
364 
365   /**
366    * Executed for replies received by the local UA.
367    */
368   virtual void onRxReply(const AmSipReply& reply);
369 
370   /**
371    * Updates remote_uri if necessary.
372    *
373    * Note: this method is offered for inherited classes
374    *       implementing dialog functionnalities. It is
375    *       not used by the basic class.
376    */
377   void updateDialogTarget(const AmSipReply& reply);
378 
379   /** @return 0 on success */
380   virtual int reply(const AmSipRequest& req,
381 		    unsigned int  code,
382 		    const string& reason,
onRxReplyStatus(const AmSipReply & reply)383 		    const AmMimeBody* body = NULL,
384 		    const string& hdrs = "",
385 		    int flags = 0);
386 
387   /** @return 0 on success */
388   virtual int sendRequest(const string& method,
389 			  const AmMimeBody* body = NULL,
390 			  const string& hdrs = "",
391 			  int flags = 0,
392 			  int max_forwards = -1);
393 
394   /**
395    * Terminates pending UAS/UAC transactions
396    */
397   virtual void finalize() {
398     termUasTrans();
399     termUacTrans();
400   }
401 
402   virtual void dropTransactions();
403 
404   /**
405    * This method should only be used to send responses
406    * to requests which are not referenced by any dialog.
407    *
408    * WARNING: If the request has already been referenced
409    * (see uas_trans), this method cannot mark the request
410    * as replied, thus leaving it in the pending state forever.
termUasTrans()411    */
412   static int reply_error(const AmSipRequest& req,
413 			 unsigned int  code,
414 			 const string& reason,
415 			 const string& hdrs = "",
416 			 msg_logger* logger = NULL);
417 
418   /* dump transaction information (DBG) */
419   void dump();
420 
421   /**
422    * Enable or disable message logger
423    */
424   void setMsgLogger(msg_logger* logger);
425 
426   /**
427    * Get message logger
termUacTrans()428    */
429   msg_logger* getMsgLogger() { return logger; }
430 };
431 
432 /**
433  * \brief base class for SIP request/reply event handler
434  */
435 class AmBasicSipEventHandler
436 {
437  public:
438 
439   /** Hook called when a request has been received */
440   virtual void onSipRequest(const AmSipRequest& req) {}
441 
dropTransactions()442   /** Hook called when a reply has been received */
443   virtual void onSipReply(const AmSipRequest& req,
444 			  const AmSipReply& reply,
445 			  AmBasicSipDialog::Status old_status) {}
446 
onRxReplySanity(const AmSipReply & reply)447   /** Hook called before a request is sent */
448   virtual void onSendRequest(AmSipRequest& req, int& flags) {}
449 
450   /** Hook called before a reply is sent */
451   virtual void onSendReply(const AmSipRequest& req,
452 			   AmSipReply& reply, int& flags) {}
453 
454   /** Hook called after a request has been sent */
455   virtual void onRequestSent(const AmSipRequest& req) {}
456 
457   /** Hook called after a reply has been sent */
458   virtual void onReplySent(const AmSipRequest& req, const AmSipReply& reply) {}
459 
460   /**
461    * Hook called when the all dialog usages should be terminated
462    * after a reply received from the far end, or a locally generated
463    * timeout (408).
464    */
465   virtual void onRemoteDisappeared(const AmSipReply& reply) {}
466 
onRxReply(const AmSipReply & reply)467   /**
468    * Hook called when the all dialog usages should be terminated
469    * before a local reply is sent.
470    */
471   virtual void onLocalTerminate(const AmSipReply& reply) {}
472 
473   /**
474    * Hook called when either a received request or
475    * reply has been rejected by the local SIP UA layer.
476    */
477   virtual void onFailure() {}
478 
479   // called upon finishing either UAC or UAS transaction
480   virtual void onTransFinished() { }
481 
482 
483   virtual ~AmBasicSipEventHandler() {}
484 };
485 
486 #endif
487