1 /*
2  * msrp.h
3  *
4  * Support for RFC 4975 Message Session Relay Protocol (MSRP)
5  *
6  * Open Phone Abstraction Library (OPAL)
7  *
8  * Copyright (c) 2008 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: 27149 $
27  * $Author: rjongbloed $
28  * $Date: 2012-03-07 18:32:36 -0600 (Wed, 07 Mar 2012) $
29  */
30 
31 #ifndef OPAL_IM_MSRP_H
32 #define OPAL_IM_MSRP_H
33 
34 #include <ptlib.h>
35 #include <opal/buildopts.h>
36 #include <opal/rtpconn.h>
37 #include <opal/manager.h>
38 #include <opal/mediastrm.h>
39 #include <opal/mediatype.h>
40 #include <im/im.h>
41 #include <ptclib/inetprot.h>
42 #include <ptclib/guid.h>
43 #include <ptclib/mime.h>
44 
45 #if OPAL_SIP
46 #include <sip/sdp.h>
47 #endif
48 
49 #if OPAL_HAS_MSRP
50 
51 class OpalMSRPMediaType : public OpalIMMediaType
52 {
53   public:
54     OpalMSRPMediaType();
55     virtual OpalMediaSession * CreateMediaSession(OpalConnection & conn, unsigned sessionID) const;
56 
57 #if OPAL_SIP
58     SDPMediaDescription * CreateSDPMediaDescription(const OpalTransportAddress & localAddress);
59 #endif
60 };
61 
62 
63 ////////////////////////////////////////////////////////////////////////////
64 //
65 //  Ancestor for all MSRP encoding types
66 //
67 
68 class OpalMSRPEncoding {
69 };
70 
71 
72 ////////////////////////////////////////////////////////////////////////////
73 //
74 //  Ancestor for MSRP protocol
75 //
76 
77 class MSRPProtocol : public PInternetProtocol
78 {
79   public:
80     enum Commands {
81       SEND,
82       REPORT,
83       NumCommands
84     };
85 
86     static const unsigned MaximumMessageLength = 1024;
87 
88     class Message
89     {
90       public:
91         struct Chunk {
ChunkChunk92           Chunk(const PString & id, unsigned from, unsigned len)
93             : m_chunkId(id), m_rangeFrom(from + 1), m_rangeTo(from + len) { }
94 
95           PString m_chunkId;
96           unsigned m_rangeFrom;
97           unsigned m_rangeTo;
98         };
99         typedef std::vector<Chunk> ChunkList;
100         ChunkList m_chunks;
101 
102         PString m_id;
103         PURL    m_fromURL;
104         PURL    m_toURL;
105         PString m_contentType;
106         unsigned m_length;
107     };
108 
109     MSRPProtocol();
110 
111     bool SendSEND(
112       const PURL & from,
113       const PURL & to,
114       const PString & text,
115       const PString & contentType,
116       PString & messageId
117     );
118 
119     bool SendChunk(
120       const PString & transactionId,
121       const PString toUrl,
122       const PString fromUrl,
123       const PMIMEInfo & mime,
124       const PString & body
125     );
126 
127     bool SendResponse(const PString & chunkId,
128                              unsigned response,
129                       const PString & text,
130                       const PString & toUrl,
131                       const PString & fromUrl);
132 
133     bool SendREPORT(const PString & chunkId,
134                     const PString & toUrl,
135                     const PString & fromUrl,
136                   const PMIMEInfo & mime);
137 
138     bool ReadMessage(
139       int & command,
140       PString & chunkId,
141       PMIMEInfo & mime,
142       PString & body
143     );
144 
145     //typedef std::map<std::string, Message> MessageMap;
146     //MessageMap m_messageMap;
147     PMutex m_mutex;
148 };
149 
150 ////////////////////////////////////////////////////////////////////////////
151 //
152 //
153 //
154 
155 class OpalMSRPManager : public PObject
156 {
157   public:
158     enum {
159       DefaultPort = 2855
160     };
161 
162     //
163     //  Create an MSRP manager. This is a singleton class
164     //
165     OpalMSRPManager(OpalManager & opal, WORD port = DefaultPort);
166     ~OpalMSRPManager();
167 
168     //
169     //  Get the local port for the MSRP manager
170     //
171     bool GetLocalPort(WORD & port);
172 
173     //
174     // Information about a connection to another MSRP manager
175     //
176     class Connection : public PSafeObject {
177       public:
178         Connection(OpalMSRPManager & manager, const std::string & key, MSRPProtocol * protocol = NULL);
179         ~Connection();
180 
181         //
182         //  Start handler thread for a connection
183         //
184         void StartHandler();
185 
186         //
187         //  Handler thread for a connection
188         //
189         void HandlerThread();
190 
191         OpalMSRPManager & m_manager;
192         std::string m_key;
193         MSRPProtocol * m_protocol;
194         bool m_running;
195         PThread * m_handlerThread;
196         bool m_originating;
197         PAtomicInteger m_refCount;
198     };
199 
200     //
201     //  Get the connection to use for communicating with a remote URL
202     //
203     PSafePtr<Connection> OpenConnection(
204       const PURL & localURL,
205       const PURL & remoteURL
206     );
207 
208     //
209     //  close a connection
210     //
211     bool CloseConnection(
212       PSafePtr<OpalMSRPManager::Connection> & connection
213     );
214 
215     //
216     //  Create a new MSRP session ID
217     //
218     std::string CreateSessionID();
219 
220     //
221     //  return session ID as a path
222     //
223     PURL SessionIDToURL(const OpalTransportAddress & addr, const std::string & id);
224 
225     //
226     //  Main listening thread for new connections
227     //
228     void ListenerThread();
229 
230     struct IncomingMSRP {
231       int       m_command;
232       PString   m_chunkId;
233       PMIMEInfo m_mime;
234       PString   m_body;
235       PSafePtr<Connection> m_connection;
236     };
237 
238     //
239     // dispatch an incoming MSRP message to the correct callback
240     //
241     void DispatchMessage(
242       IncomingMSRP & incomingMsg
243     );
244 
245     typedef PNotifierTemplate<IncomingMSRP &> CallBack;
246 
247     void SetNotifier(
248       const PURL & localUrl,
249       const PURL & remoteURL,
250       const CallBack & notifier
251     );
252 
253     void RemoveNotifier(
254       const PURL & localUrl,
255       const PURL & remoteURL
256     );
257 
GetOpalManager()258     OpalManager & GetOpalManager() { return opalManager; }
259 
260   protected:
261     OpalManager & opalManager;
262     WORD m_listenerPort;
263     PMutex mutex;
264     PAtomicInteger lastID;
265     PTCPSocket m_listenerSocket;
266     PThread * m_listenerThread;
267 
268     PMutex m_connectionInfoMapAddMutex;
269     typedef std::map<std::string, PSafePtr<Connection> > ConnectionInfoMapType;
270     ConnectionInfoMapType m_connectionInfoMap;
271 
272     typedef std::map<std::string, CallBack> CallBackMap;
273     CallBackMap m_callBacks;
274     PMutex m_callBacksMutex;
275 
276   private:
277     static OpalMSRPManager * msrp;
278 };
279 
280 ////////////////////////////////////////////////////////////////////////////
281 
282 /** Class for carrying MSRP session information
283   */
284 class OpalMSRPMediaSession : public OpalMediaSession
285 {
286   PCLASSINFO(OpalMSRPMediaSession, OpalMediaSession);
287   public:
288     OpalMSRPMediaSession(OpalConnection & connection, unsigned sessionId);
289     OpalMSRPMediaSession(const OpalMSRPMediaSession & _obj);
290     ~OpalMSRPMediaSession();
291 
292     bool Open(const PURL & remoteParty);
293 
294     virtual void Close();
295 
Clone()296     virtual PObject * Clone() const { return new OpalMSRPMediaSession(*this); }
297 
IsActive()298     virtual bool IsActive() const { return true; }
299 
IsRTP()300     virtual bool IsRTP() const { return false; }
301 
HasFailed()302     virtual bool HasFailed() const { return false; }
303 
304     virtual OpalTransportAddress GetLocalMediaAddress() const;
305 
GetLocalURL()306     PURL GetLocalURL() const { return m_localUrl; }
GetRemoteURL()307     PURL GetRemoteURL() const { return m_remoteUrl; }
SetRemoteURL(const PURL & url)308     void SetRemoteURL(const PURL & url) { m_remoteUrl = url; }
309 
310     virtual void SetRemoteMediaAddress(const OpalTransportAddress &, const OpalMediaFormatList & );
311 
312     virtual bool WritePacket(
313       RTP_DataFrame & frame
314     );
315 
316     PBoolean ReadData(
317       BYTE * data,
318       PINDEX length,
319       PINDEX & read
320     );
321 
322 #if OPAL_SIP
323     virtual SDPMediaDescription * CreateSDPMediaDescription(
324       const OpalTransportAddress & localAddress
325     );
326 #endif
327 
328     virtual OpalMediaStream * CreateMediaStream(
329       const OpalMediaFormat & mediaFormat,
330       unsigned sessionID,
331       PBoolean isSource
332     );
333 
GetManager()334     OpalMSRPManager & GetManager() { return m_manager; }
335 
336     bool OpenMSRP(const PURL & remoteUrl);
337     void CloseMSRP();
338 
339     void SetConnection(PSafePtr<OpalMSRPManager::Connection> & conn);
340 
341     OpalMSRPManager & m_manager;
342     bool m_isOriginating;
343     std::string m_localMSRPSessionId;
344     PURL m_localUrl;
345     PURL m_remoteUrl;
346     PSafePtr<OpalMSRPManager::Connection> m_connectionPtr;
347     OpalTransportAddress m_remoteAddress;
348 };
349 
350 ////////////////////////////////////////////////////////////////////////////
351 
352 class OpalMSRPMediaStream : public OpalIMMediaStream
353 {
354   public:
355     OpalMSRPMediaStream(
356       OpalConnection & conn,
357       const OpalMediaFormat & mediaFormat, ///<  Media format for stream
358       unsigned sessionID,                  ///<  Session number for stream
359       bool isSource,                       ///<  Is a source stream
360       OpalMSRPMediaSession & msrpSession
361 
362     );
363 
364     ~OpalMSRPMediaStream();
365 
RequiresPatchThread()366     virtual PBoolean RequiresPatchThread() const   { return !isSource; }
367 
368     /**Read raw media data from the source media stream.
369        The default behaviour reads from the PChannel object.
370       */
371     virtual PBoolean ReadPacket(
372       RTP_DataFrame & frame
373     );
374 
375     /**Write raw media data to the sink media stream.
376        The default behaviour writes to the PChannel object.
377       */
378     virtual PBoolean WritePacket(
379       RTP_DataFrame & frame
380     );
381 
382     virtual bool Open();
383 
GetRemoteURL()384     PURL GetRemoteURL() const           { return m_msrpSession.GetRemoteURL(); }
SetRemoteURL(const PURL & url)385     void SetRemoteURL(const PURL & url) { m_msrpSession.SetRemoteURL(url); }
386 
387     PDECLARE_NOTIFIER2(OpalMSRPManager, OpalMSRPMediaStream, OnReceiveMSRP, OpalMSRPManager::IncomingMSRP &);
388 
389 
390   //@}
391   protected:
392     OpalMSRPMediaSession & m_msrpSession;
393     PString m_remoteParty;
394     RFC4103Context m_rfc4103Context;
395 };
396 
397 //                       schemeName,user,   passwd, host,   defUser,defhost, query,  params, frags,  path,   rel,    port
398 
399 #endif // OPAL_HAS_MSRP
400 
401 #endif // OPAL_IM_MSRP_H
402 
403