1 /*
2  * Copyright (C) 2002-2003 Fhg Fokus
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 AmB2BSession.h */
28 #ifndef AmB2BSession_h
29 #define AmB2BSession_h
30 
31 #include "AmSession.h"
32 #include "AmSipDialog.h"
33 #include "sip/hash.h"
34 #include "AmB2BMedia.h"
35 #include "AmSipSubscription.h"
36 
37 #define MAX_RELAY_STREAMS 3 // voice, video, rtt
38 
39 enum { B2BTerminateLeg,
40        B2BConnectLeg,
41        B2BSipRequest,
42        B2BSipReply,
43        B2BMsgBody };
44 
45 /** \brief base class for event in B2B session */
46 struct B2BEvent: public AmEvent
47 {
48   enum B2BEventType {
49     B2BCore,
50     B2BApplication,
51   } ev_type;
52 
53   map<string, string> params;
54 
B2BEventB2BEvent55  B2BEvent(int ev_id)
56    : AmEvent(ev_id), ev_type(B2BCore)
57   {}
58 
B2BEventB2BEvent59  B2BEvent(int ev_id, B2BEventType ev_type)
60    : AmEvent(ev_id), ev_type(ev_type)
61   { }
62 
B2BEventB2BEvent63  B2BEvent(int ev_id, B2BEventType ev_type, map<string, string> params)
64    : AmEvent(ev_id), ev_type(ev_type), params(params)
65   { }
66 };
67 
68 /** \brief base class for SIP event in B2B session */
69 struct B2BSipEvent: public B2BEvent
70 {
71   bool forward;
72 
B2BSipEventB2BSipEvent73   B2BSipEvent(int ev_id, bool forward)
74     : B2BEvent(ev_id),
75        forward(forward)
76   {}
77 };
78 
79 /** \brief SIP request in B2B session */
80 struct B2BSipRequestEvent: public B2BSipEvent
81 {
82   AmSipRequest req;
83 
B2BSipRequestEventB2BSipRequestEvent84   B2BSipRequestEvent(const AmSipRequest& req, bool forward)
85     : B2BSipEvent(B2BSipRequest,forward),
86        req(req)
87   { }
88 };
89 
90 /** \brief SIP reply in B2B session */
91 struct B2BSipReplyEvent: public B2BSipEvent
92 {
93   AmSipReply reply;
94   string trans_method;
95   string sender_ltag;
96 
B2BSipReplyEventB2BSipReplyEvent97  B2BSipReplyEvent(const AmSipReply& reply, bool forward,
98 		  string trans_method, string sender_ltag)
99    : B2BSipEvent(B2BSipReply,forward),
100     reply(reply), trans_method(trans_method), sender_ltag(sender_ltag)
101   { }
102 };
103 
104 /** \brief trigger connecting the callee leg in B2B session */
105 struct B2BConnectEvent: public B2BEvent
106 {
107   string remote_party;
108   string remote_uri;
109 
110   AmMimeBody body;
111   string hdrs;
112 
113   bool relayed_invite;
114   unsigned int r_cseq;
115 
B2BConnectEventB2BConnectEvent116   B2BConnectEvent(const string& remote_party,
117 		  const string& remote_uri)
118     : B2BEvent(B2BConnectLeg),
119     remote_party(remote_party),
120     remote_uri(remote_uri),
121     relayed_invite(false),
122     r_cseq(0)
123   {}
124 };
125 
126 /**
127  * \brief Base class for Sessions in B2BUA mode.
128  *
129  * It has two legs as independent sessions:
130  * Callee- and caller-leg.
131  */
132 class AmB2BSession: public AmSession, protected RelayController
133 {
134  public:
135 
136   enum RTPRelayMode {
137     /* audio will go directly between caller and callee
138      * SDP bodies of relayed requests are filtered */
139     RTP_Direct,
140 
141     /* audio will be realyed through us
142      * SDP bodies of relayed requests are filtered
143      * and connection addresses are replaced by us
144      */
145     RTP_Relay,
146 
147     /*
148      * similar to RTP_Relay, but additionally transcoding
149      * might be used depending on payload IDs
150      */
151     RTP_Transcoding
152   };
153 
154 private:
155   /** local tag of the other leg */
156   string other_id;
157 
158   /** CSeq map for REFER subscriptions */
159   map<unsigned int, unsigned int> refer_id_map;
160 
161  protected:
162   /** Tell if the session should
163    *  process SIP request itself
164    * or only relay them (B2B mode).
165    */
166   bool sip_relay_only;
167 
168   bool a_leg;
169 
170   /**
171    * Requests which have been relayed
172    * from the other leg and sent as SIP
173    */
174   TransMap relayed_req;
175 
176   /** Requests received for relaying */
177   TransMap recvd_req;
178 
179   /** CSeq and Max-Forwards of the INVITE that established this call */
180   unsigned int est_invite_cseq;
181   unsigned int est_invite_other_cseq;
182   unsigned int est_invite_max_forwards;
183 
184   /** SUBSCRIBE/NOTIFY handling */
185   AmSipSubscription* subs;
186 
187   /** body of established session */
188   AmMimeBody established_body;
189   /** hash of body (from o-line) */
190   uint32_t body_hash;
191   /** save current session description (SDP) */
192   virtual bool saveSessionDescription(const AmMimeBody& body);
193   /** @return whether session description (SDP) has changed */
194   virtual bool updateSessionDescription(const AmMimeBody& body);
195 
196   /** reset relation with other leg */
197   virtual void clear_other();
198 
199   /** send a relayed SIP Request */
200   int relaySip(const AmSipRequest& req);
201 
202   /** send a relayed SIP Reply */
203   int relaySip(const AmSipRequest& orig, const AmSipReply& reply);
204 
205  public:
206 
207   void relayError(const string &method, unsigned cseq, bool forward, int sip_code, const char *reason);
208   void relayError(const string &method, unsigned cseq, bool forward, int err_code);
209 
210  protected:
211   /** Terminate our leg and forget the other. */
212   virtual void terminateLeg();
213 
214   /** Terminate the other leg and forget it.*/
215   virtual void terminateOtherLeg();
216 
217 
218   /** @see AmSession */
219   virtual void updateUACTransCSeq(unsigned int old_cseq, unsigned int new_cseq);
220 
221   void onSipRequest(const AmSipRequest& req);
222   void onSipReply(const AmSipRequest& req, const AmSipReply& reply,
223 		  AmBasicSipDialog::Status old_dlg_status);
224 
225   void onRequestSent(const AmSipRequest& req);
226   void onReplySent(const AmSipRequest& req, const AmSipReply& reply);
227 
228   void onInvite2xx(const AmSipReply& reply);
229 
230   int onSdpCompleted(const AmSdp& local_sdp, const AmSdp& remote_sdp);
231 
232   void onRemoteDisappeared(const AmSipReply& reply);
233 
234   void onRtpTimeout();
235   void onSessionTimeout();
236   void onNoAck(unsigned int cseq);
237 
238   /** send re-INVITE with established session description
239    *  @return 0 on success
240    */
241   int sendEstablishedReInvite();
242 
243   /** do session refresh */
244   bool refresh(int flags = 0);
245 
246   /** @see AmEventQueue */
247   void process(AmEvent* event);
248 
249   /** @see AmEventQueue */
250   void finalize();
251 
252   /** B2BEvent handler */
253   virtual void onB2BEvent(B2BEvent* ev);
254 
255   /** handle BYE on other leg
256       @return whether BYE is processed and should not be relayed via SIP
257       if true, the application must have handled the BYE
258       (i.e. sent 200 OK to the BYE using relayError())
259    */
260   virtual bool onOtherBye(const AmSipRequest& req);
261 
262   /**
263    * Reply received from other leg has been replied
264    * @return true if reply was processed (should be absorbed)
265    * @return false if reply was not processed
266    */
267   virtual bool onOtherReply(const AmSipReply& reply);
268 
269   AmB2BSession(const string& other_local_tag = "", AmSipDialog* p_dlg=NULL,
270 	       AmSipSubscription* p_subs=NULL);
271 
272   virtual ~AmB2BSession();
273 
274   /** flag to enable RTP relay mode */
275   RTPRelayMode rtp_relay_mode;
276   /** force symmetric RTP */
277   bool rtp_relay_force_symmetric_rtp;
278   /** transparent seqno for RTP relay */
279   bool rtp_relay_transparent_seqno;
280   /** transparent SSRC for RTP relay */
281   bool rtp_relay_transparent_ssrc;
282   /** If true, transcoded audio is injected into
283       the inband DTMF detector */
284   bool enable_dtmf_transcoding;
285   /** filter RTP DTMF (2833 / 4733) packets */
286   bool enable_dtmf_rtp_filtering;
287   /** detect DTMF through RTP DTMF (2833 / 4733) packets */
288   bool enable_dtmf_rtp_detection;
289 
290   /** Low fidelity payloads for which inband DTMF
291       transcoding should be used */
292   vector<SdpPayload> lowfi_payloads;
293 
294   /** clear our and the other side's RTP streams from RTPReceiver */
295   void clearRtpReceiverRelay();
296   /** update remote connection in relay_streams */
297   void updateRelayStreams(const AmMimeBody& body,
298 			  AmSdp& parser_sdp);
299 
300   /** replace connection with our address */
301   void updateLocalBody(AmMimeBody& body);
302 
303   /** Called when SDP relayed from other leg should be sent to the remote party.
304    * Default implementation updates connection address and ports. */
305   virtual void updateLocalSdp(AmSdp &sdp);
306 
307   /**
308    * Returns true and sets mapped_id if refer_id corresponds to an existing
309    * refer event subscription which has been relayed.
310    */
311   bool getMappedReferID(unsigned int refer_id, unsigned int& mapped_id) const;
312   virtual void insertMappedReferID(unsigned int refer_id, unsigned int mapped_id);
313 
314  public:
315 
setOtherId(const string & n_other_id)316   virtual void setOtherId(const string& n_other_id) {
317     other_id = n_other_id;
318   }
getOtherId()319   virtual const string& getOtherId() const { return other_id; }
320 
321   /** Relay one event to the other side. @return 0 on success */
322   virtual int relayEvent(AmEvent* ev);
323 
324   void set_sip_relay_only(bool r);
325 
326   /** set RTP relay mode (possibly initiaze by given INVITE) */
327   virtual void setRtpRelayMode(RTPRelayMode mode);
328 
329   /** link RTP streams of other_session to our streams */
getRtpRelayMode()330   RTPRelayMode getRtpRelayMode() const { return rtp_relay_mode; }
getRtpRelayForceSymmetricRtp()331   bool getRtpRelayForceSymmetricRtp() const { return rtp_relay_force_symmetric_rtp; }
getEnableDtmfTranscoding()332   bool getEnableDtmfTranscoding() const { return enable_dtmf_transcoding; }
getEnableDtmfRtpFiltering()333   bool getEnableDtmfRtpFiltering() const { return enable_dtmf_rtp_filtering; }
getEnableDtmfRtpDetection()334   bool getEnableDtmfRtpDetection() const { return enable_dtmf_rtp_detection; }
335   void getLowFiPLs(vector<SdpPayload>& lowfi_payloads) const;
336 
337   virtual void setRtpInterface(int relay_interface);
338   virtual void setRtpRelayForceSymmetricRtp(bool force_symmetric);
339   void setRtpRelayTransparentSeqno(bool transparent);
340   void setRtpRelayTransparentSSRC(bool transparent);
341 
342   void setEnableDtmfTranscoding(bool enable);
343   void setEnableDtmfRtpFiltering(bool enable);
344   void setEnableDtmfRtpDetection(bool enable);
345   void setLowFiPLs(const vector<SdpPayload>& lowfi_payloads);
346 
getRtpRelayTransparentSeqno()347   bool getRtpRelayTransparentSeqno() { return rtp_relay_transparent_seqno; }
getRtpRelayTransparentSSRC()348   bool getRtpRelayTransparentSSRC() { return rtp_relay_transparent_ssrc; }
349 
350   /* -------------- media processing -------------- */
351 
352   private:
353     AmB2BMedia *media_session;
354 
355   public:
356     virtual void setMediaSession(AmB2BMedia *new_session);
getMediaSession()357     AmB2BMedia *getMediaSession() { return media_session; }
358 
359     // see RelayController
360     virtual void computeRelayMask(const SdpMedia &m, bool &enable, PayloadMask &mask);
361 };
362 
363 class AmB2BCalleeSession;
364 
365 /** \brief Caller leg of a B2B session */
366 class AmB2BCallerSession: public AmB2BSession
367 {
368  public:
369   enum CalleeStatus {
370     None=0,
371     NoReply,
372     Ringing,
373     Connected
374   };
375 
376  private:
377   // Callee Status
378   CalleeStatus callee_status;
379 
380   int  reinviteCaller(const AmSipReply& callee_reply);
381 
382  protected:
383   AmSipRequest invite_req;
384   virtual void createCalleeSession();
385   int relayEvent(AmEvent* ev);
386 
387   /** Tell if the session should
388    *  relay early media SDPs to
389    *  caller leg
390    */
391   bool sip_relay_early_media_sdp;
392 
393  public:
394   AmB2BCallerSession();
395   virtual ~AmB2BCallerSession();
396 
getCalleeStatus()397   CalleeStatus getCalleeStatus() { return callee_status; }
setCalleeStatus(CalleeStatus c)398   void setCalleeStatus(CalleeStatus c) { callee_status = c; }
399 
400   virtual AmB2BCalleeSession* newCalleeSession();
401 
402   void connectCallee(const string& remote_party,
403 		     const string& remote_uri,
404 		     bool relayed_invite = false);
405 
getOriginalRequest()406   const AmSipRequest& getOriginalRequest() { return invite_req; }
407 
408   // @see AmSession
409   void onInvite(const AmSipRequest& req);
410   void onInvite2xx(const AmSipReply& reply);
411   void onCancel(const AmSipRequest& req);
412   void onBye(const AmSipRequest& req);
413 
414   void onRemoteDisappeared(const AmSipReply& reply);
415 
416   void onSystemEvent(AmSystemEvent* ev);
417 
418   // @see AmB2BSession
419   void terminateLeg();
420   void terminateOtherLeg();
421   virtual void onB2BEvent(B2BEvent* ev);
422 
getInviteReq()423   AmSipRequest* getInviteReq() { return &invite_req; }
424 
425   void set_sip_relay_early_media_sdp(bool r);
426 
427   /** initialize RTP relay mode, if rtp_relay_enabled
428       must be called *before* callee_session is started
429    */
430   void initializeRTPRelay(AmB2BCalleeSession* callee_session);
431 };
432 
433 /** \brief Callee leg of a B2B session */
434 class AmB2BCalleeSession: public AmB2BSession
435 {
436  public:
437   AmB2BCalleeSession(const string& other_local_tag);
438   AmB2BCalleeSession(const AmB2BCallerSession* caller);
439 
440   virtual ~AmB2BCalleeSession();
441 
442   virtual void onB2BEvent(B2BEvent* ev);
443 };
444 
445 #endif
446