1 /*
2  * rtpconn.h
3  *
4  * Connection abstraction
5  *
6  * Open Phone Abstraction Library (OPAL)
7  *
8  * Copyright (C) 2007 Post Increment
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Open Phone Abstraction Library.
21  *
22  * The Initial Developer of the Original Code is Post Increment
23  *
24  * Contributor(s): ______________________________________.
25  *
26  * $Revision: 26728 $
27  * $Author: rjongbloed $
28  * $Date: 2011-12-01 22:59:14 -0600 (Thu, 01 Dec 2011) $
29  */
30 
31 #ifndef OPAL_OPAL_RTPCONN_H
32 #define OPAL_OPAL_RTPCONN_H
33 
34 #ifdef P_USE_PRAGMA
35 #pragma interface
36 #endif
37 
38 #include <opal/buildopts.h>
39 
40 #include <opal/connection.h>
41 #include <opal/mediatype.h>
42 
43 #ifdef OPAL_ZRTP
44 
45 class OpalZRTPStreamInfo {
46   public:
47     virtual bool Open() = 0;
48     virtual RTP_UDP * CreateRTPSession(OpalConnection & conn, unsigned sessionId, bool remoteIsNat) = 0;
49 };
50 
51 class OpalZRTPConnectionInfo {
52   public:
53     virtual bool Open() = 0;
54     virtual RTP_UDP * CreateRTPSession(OpalConnection & conn, unsigned sessionId, bool remoteIsNat) = 0;
55 
56     PMutex mutex;
57 };
58 
59 #endif // OPAL_ZRTP
60 
61 
62 class OpalRTPEndPoint;
63 
64 //#ifdef HAS_LIBZRTP
65 //#ifndef __ZRTP_TYPES_H__
66 //struct zrtp_conn_ctx_t;
67 //#endif
68 //#endif
69 
70 /** Class for carrying media session information
71   */
72 class OpalMediaSession : public PObject
73 {
74     PCLASSINFO(OpalMediaSession, PObject);
75   public:
76     OpalMediaSession(OpalConnection & conn, const OpalMediaType & _mediaType, unsigned sessionId);
77     OpalMediaSession(const OpalMediaSession & _obj);
78 
79     virtual void Close() = 0;
80 
81     virtual PObject * Clone() const = 0;
82 
83     virtual bool IsActive() const = 0;
84 
85     virtual bool IsRTP() const = 0;
86 
87     virtual bool HasFailed() const = 0;
88 
89     virtual OpalTransportAddress GetLocalMediaAddress() const = 0;
90 
SetRemoteMediaAddress(const OpalTransportAddress &,const OpalMediaFormatList &)91     virtual void SetRemoteMediaAddress(const OpalTransportAddress &, const OpalMediaFormatList & ) { }
92 
93 #if OPAL_SIP
94     virtual SDPMediaDescription * CreateSDPMediaDescription(
95       const OpalTransportAddress & localAddress
96     ) = 0;
97 #endif
98 
99     virtual OpalMediaStream * CreateMediaStream(
100       const OpalMediaFormat & mediaFormat,
101       unsigned sessionID,
102       PBoolean isSource
103     ) = 0;
104 
105     OpalConnection & connection;
106     OpalMediaType mediaType;     // media type for session
107     unsigned sessionId;          // unique session ID
108 };
109 
110 
111 /** Class for carrying RTP session information
112   */
113 class OpalRTPMediaSession : public OpalMediaSession
114 {
115   PCLASSINFO(OpalRTPMediaSession, OpalMediaSession);
116   public:
117     OpalRTPMediaSession(
118       OpalConnection & conn,
119       const OpalMediaType & mediaType,
120       unsigned sessionId
121     );
122     OpalRTPMediaSession(const OpalRTPMediaSession & obj);
123     ~OpalRTPMediaSession();
124 
Clone()125     PObject * Clone() const { return new OpalRTPMediaSession(*this); }
126 
127     void Attach(RTP_Session * rtpSession);
128 
129     virtual void Close();
130 
IsActive()131     virtual bool IsActive() const { return rtpSession != NULL; }
132 
IsRTP()133     virtual bool IsRTP() const { return true; }
134 
HasFailed()135     virtual bool HasFailed() const { return (rtpSession != NULL) && (rtpSession->HasFailed() || (rtpSession->GetPacketsReceived() == 0)); }
136 
137     virtual OpalTransportAddress GetLocalMediaAddress() const;
138 
139 #if OPAL_SIP
140     virtual SDPMediaDescription * CreateSDPMediaDescription(
141       const OpalTransportAddress & localAddress
142     );
143 #endif
144 
145     virtual OpalMediaStream * CreateMediaStream(
146       const OpalMediaFormat & mediaFormat,
147       unsigned sessionID,
148       PBoolean isSource
149     );
150 
GetSession()151     RTP_Session * GetSession() const { return rtpSession; }
152 
153   protected:
154     RTP_Session * rtpSession;    // RTP session
155 };
156 
157 /**This class manages the RTP sessions for an OpalRTPConnection
158  */
159 class OpalRTPSessionManager : public PObject
160 {
161     PCLASSINFO(OpalRTPSessionManager , PObject);
162   public:
163   /**@name Construction */
164   //@{
165     /**Construct new session manager database.
166       */
167     OpalRTPSessionManager(
168       OpalRTPConnection & connection ///< Owner connection for RTP sessions
169     );
170 
171     /// Destroy sessions, unlinking from connection
172     ~OpalRTPSessionManager();
173 
174     ///Copy constructor - maintain list in OpalRTPConnection
175     OpalRTPSessionManager(const OpalRTPSessionManager & other);
176 
177     /// Assignment of RTP session managers.
178     void operator=(const OpalRTPSessionManager & other) { sessions = other.sessions; }
179   //@}
180 
181   /**@name Operations */
182   //@{
183     /**Get next available session ID for the media type.
184       */
185     unsigned GetNextSessionID();
186 
187     /**Add an RTP session for the specified ID.
188 
189        This function MUST be called only after the UseSession() function has
190        returned NULL. The mutex flag is left locked in that case. This
191        function expects the mutex to be locked and unlocks it automatically.
192       */
193     void AddSession(
194       RTP_Session * session,          ///<  Session to add.
195       const OpalMediaType & mediaType ///< initial media type for this session
196     );
197     void AddMediaSession(
198       OpalMediaSession * session,          ///<  Session to add.
199       const OpalMediaType & mediaType ///< initial media type for this session
200     );
201 
202     /**Release the session.
203      */
204     virtual void CloseSession(
205       unsigned sessionID     ///<  Session ID to release, 0 indicates all
206     );
207 
208     /**Get a session for the specified ID.
209      */
210     RTP_Session * GetSession(
211       unsigned sessionID    ///<  Session ID to get.
212     ) const;
213     OpalMediaSession * GetMediaSession(
214       unsigned sessionID
215     ) const;
216 
217     /**Change the sessionID for an existing session.
218        This will adjust the RTP session and media streams.
219 
220        Return false if no such session exists.
221       */
222     bool ChangeSessionID(
223       unsigned fromSessionID,   ///< Session ID to search for
224       unsigned toSessionID      ///< Session ID to change to
225     );
226   //@}
227 
GetMutex()228     PMutex & GetMutex() { return m_mutex; }
229 
230     virtual bool AllSessionsFailing();
231 
232   protected:
233     OpalRTPConnection & m_connection;
234     PMutex m_mutex;
235 
236     PDICTIONARY(SessionDict, POrdinalKey, OpalMediaSession);
237     SessionDict sessions;
238 };
239 
240 
241 typedef OpalRTPSessionManager RTP_SessionManager;
242 
243 
244 /**This is the base class for OpalConnections that use RTP sessions,
245    such as H.323 and SIPconnections to an endpoint.
246  */
247 class OpalRTPConnection : public OpalConnection
248 {
249     PCLASSINFO(OpalRTPConnection, OpalConnection);
250   public:
251   /**@name Construction */
252   //@{
253     /**Create a new connection.
254      */
255     OpalRTPConnection(
256       OpalCall & call,                         ///<  Owner calll for connection
257       OpalRTPEndPoint & endpoint,              ///<  Owner endpoint for connection
258       const PString & token,                   ///<  Token to identify the connection
259       unsigned options = 0,                    ///<  Connection options
260       OpalConnection::StringOptions * stringOptions = NULL     ///< more complex options
261     );
262 
263     /**Destroy connection.
264      */
265     ~OpalRTPConnection();
266 
267     /**Clean up the termination of the connection.
268        This function can do any internal cleaning up and waiting on background
269        threads that may be using the connection object.
270 
271        Note that there is not a one to one relationship with the
272        OnEstablishedConnection() function. This function may be called without
273        that function being called. For example if SetUpConnection() was used
274        but the call never completed.
275 
276        Classes that override this function should make sure they call the
277        ancestor version for correct operation.
278 
279        An application will not typically call this function as it is used by
280        the OpalManager during a release of the connection.
281 
282        The default behaviour calls the OpalEndPoint function of the same name.
283       */
284     virtual void OnReleased();
285   //@}
286 
287 
288   /**@name RTP Session Management */
289   //@{
290     /**Get next available session ID for the media type.
291       */
292     virtual unsigned GetNextSessionID(
293       const OpalMediaType & mediaType,   ///< Media type of stream being opened
294       bool isSource                      ///< Stream is a source/sink
295     );
296 
297     /**Get an RTP session for the specified ID.
298        If there is no session of the specified ID, NULL is returned.
299       */
300     virtual RTP_Session * GetSession(
301       unsigned sessionID    ///<  RTP session number
302     ) const;
303     virtual OpalMediaSession * GetMediaSession(
304       unsigned sessionID    ///<  RTP session number
305     ) const;
306 
307     /**Use an RTP session for the specified ID.
308        This will find a session of the specified ID and uses it if available.
309 
310        If there is no session of the specified ID one is created.
311 
312        The type of RTP session that is created will be compatible with the
313        transport. At this time only IP (RTP over UDP) is supported.
314       */
315     virtual RTP_Session * UseSession(
316       const OpalTransport & transport,  ///<  Transport of signalling
317       unsigned sessionID,               ///<  RTP session number
318       const OpalMediaType & mediatype,  ///<  media type
319       RTP_QOS * rtpqos = NULL           ///<  Quiality of Service information
320     );
321 
322     /**Release the session.
323      */
324     virtual void CloseSession(
325       unsigned sessionID     ///<  RTP session number, 0 indicates all
326     );
327 
328     /**Create and open a new RTP session.
329        The type of RTP session that is created will be compatible with the
330        transport. At this time only IP (RTP over UDP) is supported.
331       */
332     virtual RTP_Session * CreateSession(
333       const OpalTransport & transport,
334       unsigned sessionID,
335       const OpalMediaType & mediaType,
336       RTP_QOS * rtpqos
337     );
338 
339     /** Create a new underlying RTP session instance.
340       */
341     virtual RTP_UDP * CreateRTPSession(
342       unsigned sessionId,
343       const OpalMediaType & mediaType,
344       bool remoteIsNat
345     );
346 
347     /**Change the sessionID for an existing session.
348        This will adjust the RTP session and media streams.
349 
350        Return false if no such session exists.
351       */
352     virtual bool ChangeSessionID(
353       unsigned fromSessionID,   ///< Session ID to search for
354       unsigned toSessionID      ///< Session ID to change to
355     );
356   //@}
357 
358   /**@name NAT Management */
359   //@{
360     /** Return true if the remote appears to be behind a NAT firewall
361     */
RemoteIsNAT()362     virtual PBoolean RemoteIsNAT() const
363     { return remoteIsNAT; }
364 
365     /**Determine if the RTP session needs to accommodate a NAT router.
366        For endpoints that do not use STUN or something similar to set up all the
367        correct protocol embeddded addresses correctly when a NAT router is between
368        the endpoints, it is possible to still accommodate the call, with some
369        restrictions. This function determines if the RTP can proceed with special
370        NAT allowances.
371 
372        The special allowance is that the RTP code will ignore whatever the remote
373        indicates in the protocol for the address to send RTP data and wait for
374        the first packet to arrive from the remote and will then proceed to send
375        all RTP data back to that address AND port.
376 
377        The default behaviour checks the values of the physical link
378        (localAddr/peerAddr) against the signaling address the remote indicated in
379        the protocol, eg H.323 SETUP sourceCallSignalAddress or SIP "To" or
380        "Contact" fields, and makes a guess that the remote is behind a NAT router.
381      */
382     virtual PBoolean IsRTPNATEnabled(
383       const PIPSocket::Address & localAddr,   ///< Local physical address of connection
384       const PIPSocket::Address & peerAddr,    ///< Remote physical address of connection
385       const PIPSocket::Address & signalAddr,  ///< Remotes signaling address as indicated by protocol of connection
386       PBoolean incoming                       ///< Incoming/outgoing connection
387     );
388   //@}
389 
390     /**Attaches the RFC 2833 handler to the media patch
391        This method may be called from subclasses, e.g. within
392        OnPatchMediaStream()
393       */
394     virtual void AttachRFC2833HandlerToPatch(PBoolean isSource, OpalMediaPatch & patch);
395 
396     virtual PBoolean SendUserInputTone(
397       char tone,        ///<  DTMF tone code
398       unsigned duration = 0  ///<  Duration of tone in milliseconds
399     );
400 
401     /**Meda information structure for GetMediaInformation() function.
402       */
403     struct MediaInformation {
MediaInformationMediaInformation404       MediaInformation() {
405         rfc2833  = RTP_DataFrame::IllegalPayloadType;
406         ciscoNSE = RTP_DataFrame::IllegalPayloadType;
407       }
408 
409       OpalTransportAddress data;           ///<  Data channel address
410       OpalTransportAddress control;        ///<  Control channel address
411       RTP_DataFrame::PayloadTypes rfc2833; ///<  Payload type for RFC2833
412       RTP_DataFrame::PayloadTypes ciscoNSE; ///<  Payload type for RFC2833
413     };
414   //@}
415 
416   /**@name Overrides from OpalConnection */
417   //@{
418     /**Get information on the media channel for the connection.
419        The default behaviour checked the mediaTransportAddresses dictionary
420        for the session ID and returns information based on that. It also uses
421        the rfc2833Handler variable for that part of the info.
422 
423        It is up to the descendant class to assure that the mediaTransportAddresses
424        dictionary is set correctly before OnIncomingCall() is executed.
425      */
426     virtual PBoolean GetMediaInformation(
427       unsigned sessionID,     ///<  Session ID for media channel
428       MediaInformation & info ///<  Information on media channel
429     ) const;
430 
431     /**See if the media can bypass the local host.
432 
433        The default behaviour returns true if the session is audio or video.
434      */
435     virtual PBoolean IsMediaBypassPossible(
436       unsigned sessionID                  ///<  Session ID for media channel
437     ) const;
438 
439     /**Create a new media stream.
440        This will create a media stream of an appropriate subclass as required
441        by the underlying connection protocol. For instance H.323 would create
442        an OpalRTPStream.
443 
444        The sessionID parameter may not be needed by a particular media stream
445        and may be ignored. In the case of an OpalRTPStream it us used.
446 
447        Note that media streams may be created internally to the underlying
448        protocol. This function is not the only way a stream can come into
449        existance.
450      */
451     virtual OpalMediaStream * CreateMediaStream(
452       const OpalMediaFormat & mediaFormat, ///<  Media format for stream
453       unsigned sessionID,                  ///<  Session number for stream
454       PBoolean isSource                        ///<  Is a source stream
455     );
456 
457     /**Adjust media formats available on a connection.
458        This is called by a connection after it has called
459        OpalCall::GetMediaFormats() to get all media formats that it can use so
460        that an application may remove or reorder the media formats before they
461        are used to open media streams.
462 
463        This function may also be executed by other connections in the call. If
464        this happens then the "otherConnection" parameter will be non-NULL. The
465        "local" parameter sense is relative to the "otherConnection" parameter,
466        if NULL then it is relative to "this".
467 
468        The default behaviour calls the OpalEndPoint function of the same name.
469       */
470     virtual void AdjustMediaFormats(
471       bool local,                             ///<  Media formats a local ones to be presented to remote
472       const OpalConnection * otherConnection, ///<  Other connection we are adjusting media for
473       OpalMediaFormatList & mediaFormats      ///<  Media formats to use
474     ) const;
475 
476     /**Call back when patching a media stream.
477        This function is called when a connection has created a new media
478        patch between two streams. This is usually called twice per media patch,
479        once for the source stream and once for the sink stream.
480 
481        Note this is not called within the context of the patch thread and is
482        called before that thread has started.
483       */
484     virtual void OnPatchMediaStream(
485       PBoolean isSource,        ///< Is source/sink call
486       OpalMediaPatch & patch    ///<  New patch
487     );
488 
489     /** Callback for media commands.
490         Calls the SendIntraFrameRequest on the rtp session
491 
492        @returns true if command is handled.
493       */
494     virtual bool OnMediaCommand(
495       OpalMediaStream & stream,         ///< Stream command executed on
496       const OpalMediaCommand & command  ///< Media command being executed
497     );
498   //@}
499 
500     virtual void SessionFailing(RTP_Session & session);
501 
502   protected:
503     PDECLARE_NOTIFIER(OpalRFC2833Info, OpalRTPConnection, OnUserInputInlineRFC2833);
504     PDECLARE_NOTIFIER(OpalRFC2833Info, OpalRTPConnection, OnUserInputInlineCiscoNSE);
505 
506     OpalRTPSessionManager m_rtpSessions;
507     OpalRFC2833Proto * rfc2833Handler;
508 #if OPAL_T38_CAPABILITY
509     OpalRFC2833Proto * ciscoNSEHandler;
510 #endif
511 
512     PBoolean remoteIsNAT;
513     PBoolean useRTPAggregation;
514 
515 #ifdef OPAL_ZRTP
516     bool zrtpEnabled;
517     PMutex zrtpConnInfoMutex;
518     OpalZRTPConnectionInfo * zrtpConnInfo;
519 #endif
520 };
521 
522 
523 class RTP_UDP;
524 
525 class OpalSecurityMode : public PObject
526 {
527   PCLASSINFO(OpalSecurityMode, PObject);
528   public:
529     virtual RTP_UDP * CreateRTPSession(
530       OpalRTPConnection & connection,     ///< Connection creating session (may be needed by secure connections)
531       const RTP_Session::Params & options ///< Parameters to construct with session.
532     ) = 0;
533     virtual PBoolean Open() = 0;
534 };
535 
536 #endif // OPAL_OPAL_RTPCONN_H
537