1 /*
2  * sippdu.h
3  *
4  * Session Initiation Protocol PDU support.
5  *
6  * Open Phone Abstraction Library (OPAL)
7  * Formally known as the Open H323 project.
8  *
9  * Copyright (c) 2002 Equivalence Pty. Ltd.
10  *
11  * The contents of this file are subject to the Mozilla Public License
12  * Version 1.0 (the "License"); you may not use this file except in
13  * compliance with the License. You may obtain a copy of the License at
14  * http://www.mozilla.org/MPL/
15  *
16  * Software distributed under the License is distributed on an "AS IS"
17  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18  * the License for the specific language governing rights and limitations
19  * under the License.
20  *
21  * The Original Code is Open Phone Abstraction Library.
22  *
23  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24  *
25  * Contributor(s): ______________________________________.
26  *
27  * $Revision: 29080 $
28  * $Author: rjongbloed $
29  * $Date: 2013-02-12 18:52:05 -0600 (Tue, 12 Feb 2013) $
30  */
31 
32 #ifndef OPAL_SIP_SIPPDU_H
33 #define OPAL_SIP_SIPPDU_H
34 
35 #ifdef P_USE_PRAGMA
36 #pragma interface
37 #endif
38 
39 #include <opal/buildopts.h>
40 
41 #if OPAL_SIP
42 
43 #include <ptclib/mime.h>
44 #include <ptclib/url.h>
45 #include <ptclib/http.h>
46 #include <sip/sdp.h>
47 #include <opal/rtpconn.h>
48 
49 
50 class OpalTransport;
51 class OpalTransportAddress;
52 class OpalProductInfo;
53 
54 class SIPEndPoint;
55 class SIPConnection;
56 class SIP_PDU;
57 class SIPSubscribeHandler;
58 class SIPDialogContext;
59 class SIPMIMEInfo;
60 
61 
62 /////////////////////////////////////////////////////////////////////////
63 // SIPURL
64 
65 /** This class extends PURL to include displayname, optional "<>" delimiters
66 	and extended parameters - like tag.
67 	It may be used for From:, To: and Contact: lines.
68  */
69 
70 class SIPURL : public PURL
71 {
72   PCLASSINFO(SIPURL, PURL);
73   public:
74     SIPURL();
75 
SIPURL(const PURL & url)76     SIPURL(
77       const PURL & url
78     ) : PURL(url) { }
79     SIPURL & operator=(
80       const PURL & url
81     ) { PURL::operator=(url); return *this; }
82 
83     /** str goes straight to Parse()
84       */
85     SIPURL(
86       const char * cstr,    ///<  C string representation of the URL.
87       const char * defaultScheme = NULL ///<  Default scheme for URL
88     );
89     SIPURL & operator=(
90       const char * cstr
91     ) { Parse(cstr); return *this; }
92 
93     /** str goes straight to Parse()
94       */
95     SIPURL(
96       const PString & str,  ///<  String representation of the URL.
97       const char * defaultScheme = NULL ///<  Default scheme for URL
98     );
99     SIPURL & operator=(
100       const PString & str
101     ) { Parse(str); return *this; }
102 
103     /** If name does not start with 'sip' then construct URI in the form
104         <pre><code>
105           sip:name\@host:port;transport=transport
106         </code></pre>
107         where host comes from address,
108         port is listenerPort or port from address if that was 0
109         transport is udp unless address specified tcp
110         Send name starting with 'sip' or constructed URI to Parse()
111      */
112     SIPURL(
113       const PString & name,
114       const OpalTransportAddress & address,
115       WORD listenerPort = 0
116     );
117 
118     SIPURL(
119       const OpalTransportAddress & address,
120       WORD listenerPort = 0
121     );
122     SIPURL & operator=(
123       const OpalTransportAddress & address
124     );
125 
126     SIPURL(
127       const SIPMIMEInfo & mime,
128       const char * name
129     );
130 
131     /**Compare the two SIPURLs and return their relative rank.
132        Note that does an intelligent comparison according to the rules
133        in RFC3261 Section 19.1.4.
134 
135      @return
136        <code>LessThan</code>, <code>EqualTo</code> or <code>GreaterThan</code>
137        according to the relative rank of the objects.
138      */
139     virtual Comparison Compare(
140       const PObject & obj   ///< Object to compare against.
141     ) const;
142 
143     /** Returns complete SIPURL as one string, including displayname (in
144         quotes) and address in angle brackets.
145       */
146     PString AsQuotedString() const;
147 
148     /** Returns display name only
149       */
150     PString GetDisplayName(PBoolean useDefault = true) const;
151 
SetDisplayName(const PString & str)152     void SetDisplayName(const PString & str)
153     {
154       m_displayName = str;
155     }
156 
157     /// Return string options in field parameters
GetFieldParameters()158     const PStringOptions & GetFieldParameters() const { return m_fieldParameters; }
GetFieldParameters()159           PStringOptions & GetFieldParameters()       { return m_fieldParameters; }
160 
161     /**Get the host and port as a transport address.
162       */
163     OpalTransportAddress GetHostAddress() const;
164 
165     /**Set the host and port as a transport address.
166       */
167     void SetHostAddress(const OpalTransportAddress & addr);
168 
169     enum UsageContext {
170       ExternalURI,   ///< URI used anywhere outside of protocol
171       RequestURI,    ///< Request-URI (after the INVITE)
172       ToURI,         ///< To header field
173       FromURI,       ///< From header field
174       RouteURI,      ///< Record-Route header field
175       RedirectURI,   ///< Redirect Contact header field
176       ContactURI,    ///< General Contact header field
177       RegContactURI, ///< Registration Contact header field
178       RegisterURI    ///< URI on REGISTER request line.
179     };
180 
181     /** Removes tag parm & query vars and recalculates urlString
182         (scheme, user, password, host, port & URI parms (like transport))
183         which are not allowed in the context specified, e.g. Request-URI etc
184         According to RFC3261, 19.1.1 Table 1
185       */
186     void Sanitise(
187       UsageContext context  ///< Context for URI
188     );
189 
190     /** This will adjust the current URL according to RFC3263, using DNS SRV records.
191 
192         @return FALSE if DNS is available but entry is larger than last SRV record entry,
193                 TRUE if DNS lookup fails or no DNS is available
194       */
195     PBoolean AdjustToDNS(
196       PINDEX entry = 0  /// Entry in the SRV record to adjust to
197     );
198 
199     /// Generate a unique string suitable as a dialog tag
200     static PString GenerateTag();
201 
202     /// Set a tag with a new unique ID.
203     void SetTag(
204       const PString & tag = PString::Empty(),
205       bool force = false
206     );
207 
208   protected:
209     void ParseAsAddress(const PString & name, const OpalTransportAddress & _address, WORD listenerPort = 0);
210 
211     // Override from PURL()
InternalParse(const char * cstr,const char * defaultScheme)212     virtual PBoolean InternalParse(
213       const char * cstr,
214       const char * defaultScheme
215     ) { return ReallyInternalParse(false, cstr, defaultScheme); }
216 
217     bool ReallyInternalParse(
218       bool fromField,
219       const char * cstr,
220       const char * defaultScheme
221     );
222 
223     PString        m_displayName;
224     PStringOptions m_fieldParameters;
225 };
226 
227 
228 class SIPURLList : public std::list<SIPURL>
229 {
230   public:
231     bool FromString(
232       const PString & str,
233       SIPURL::UsageContext context = SIPURL::RouteURI,
234       bool reversed = false
235     );
236     PString ToString() const;
237     friend ostream & operator<<(ostream & strm, const SIPURLList & urls);
238 };
239 
240 
241 
242 /////////////////////////////////////////////////////////////////////////
243 // SIPMIMEInfo
244 
245 /** Session Initiation Protocol MIME info container
246    This is a string dictionary: for each item mime header is key, value
247    is value.
248    Headers may be full ("From") or compact ("f"). Colons not included.
249    PMIMEInfo::ReadFrom (>>) parses from stream. That adds a header-value
250    element for each mime line. If a mime header is duplicated in the
251    stream then the additional value is appended to the existing,
252    separated by "/n".
253    PMIMEInfo::ReadFrom supports multi-line values if the next line starts
254    with a space - it just appends the next line to the existing string
255    with the separating space.
256    There is no checking of header names or values.
257    compactForm decides whether 'Set' methods store full or compact headers.
258    'Set' methods replace values, there is no method for appending except
259    ReadFrom.
260    'Get' methods work whether stored headers are full or compact.
261 
262    to do to satisfy RFC3261 (mandatory(*) & should):
263     Accept
264     Accept-Encoding
265     Accept-Language
266    *Allow
267    *Max-Forwards
268    *Min-Expires
269    *Proxy-Authenticate
270     Supported
271    *Unsupported
272    *WWW-Authenticate
273  */
274 
275 class SIPMIMEInfo : public PMIMEInfo
276 {
277   PCLASSINFO(SIPMIMEInfo, PMIMEInfo);
278   public:
279     SIPMIMEInfo(bool compactForm = false);
280 
281     virtual void PrintOn(ostream & strm) const;
282     virtual bool InternalAddMIME(const PString & fieldName, const PString & fieldValue);
283 
SetCompactForm(bool form)284     void SetCompactForm(bool form) { compactForm = form; }
285 
286     PCaselessString GetContentType(bool includeParameters = false) const;
287     void SetContentType(const PString & v);
288 
289     PCaselessString GetContentEncoding() const;
290     void SetContentEncoding(const PString & v);
291 
292     SIPURL GetFrom() const;
293     void SetFrom(const PString & v);
294 
295     SIPURL GetPAssertedIdentity() const;
296     void SetPAssertedIdentity(const PString & v);
297 
298     SIPURL GetPPreferredIdentity() const;
299     void SetPPreferredIdentity(const PString & v);
300 
301     PString GetAccept() const;
302     void SetAccept(const PString & v);
303 
304     PString GetAcceptEncoding() const;
305     void SetAcceptEncoding(const PString & v);
306 
307     PString GetAcceptLanguage() const;
308     void SetAcceptLanguage(const PString & v);
309 
310     PString GetAllow() const;
311     unsigned GetAllowBitMask() const;
312     void SetAllow(const PString & v);
313 
314     PString GetCallID() const;
315     void SetCallID(const PString & v);
316 
317     SIPURL GetContact() const;
318     bool GetContacts(SIPURLList & contacts) const;
319     void SetContact(const PString & v);
320 
321     PString GetSubject() const;
322     void SetSubject(const PString & v);
323 
324     SIPURL GetTo() const;
325     void SetTo(const PString & v);
326 
327     PString GetVia() const;
328     void SetVia(const PString & v);
329 
330     bool GetViaList(PStringList & v) const;
331     void SetViaList(const PStringList & v);
332 
333     PString GetFirstVia() const;
334     OpalTransportAddress GetViaReceivedAddress() const;
335 
336     SIPURL GetReferTo() const;
337     void SetReferTo(const PString & r);
338 
339     SIPURL GetReferredBy() const;
340     void SetReferredBy(const PString & r);
341 
342     PINDEX  GetContentLength() const;
343     void SetContentLength(PINDEX v);
344     PBoolean IsContentLengthPresent() const;
345 
346     PString GetCSeq() const;
347     void SetCSeq(const PString & v);
348 
349     PString GetDate() const;
350     void SetDate(const PString & v);
351     void SetDate(const PTime & t);
352     void SetDate(void); // set to current date
353 
354     unsigned GetExpires(unsigned dflt = UINT_MAX) const;// returns default value if not found
355     void SetExpires(unsigned v);
356 
357     PINDEX GetMaxForwards() const;
358     void SetMaxForwards(PINDEX v);
359 
360     PINDEX GetMinExpires() const;
361     void SetMinExpires(PINDEX v);
362 
363     PString GetProxyAuthenticate() const;
364     void SetProxyAuthenticate(const PString & v);
365 
366     PString GetRoute() const;
367     bool GetRoute(SIPURLList & proxies) const;
368     void SetRoute(const PString & v);
369     void SetRoute(const SIPURLList & proxies);
370 
371     PString GetRecordRoute() const;
372     bool GetRecordRoute(SIPURLList & proxies, bool reversed) const;
373     void SetRecordRoute(const PString & v);
374     void SetRecordRoute(const SIPURLList & proxies);
375 
GetCSeqIndex()376     unsigned GetCSeqIndex() const { return GetCSeq().AsUnsigned(); }
377 
378     PStringSet GetRequire() const;
379     void SetRequire(const PStringSet & v);
380     void AddRequire(const PString & v);
381 
382     PStringSet GetSupported() const;
383     void SetSupported(const PStringSet & v);
384     void AddSupported(const PString & v);
385 
386     PStringSet GetUnsupported() const;
387     void SetUnsupported(const PStringSet & v);
388     void AddUnsupported(const PString & v);
389 
390     PString GetEvent() const;
391     void SetEvent(const PString & v);
392 
393     PCaselessString GetSubscriptionState(PStringToString & info) const;
394     void SetSubscriptionState(const PString & v);
395 
396     PString GetUserAgent() const;
397     void SetUserAgent(const PString & v);
398 
399     PString GetOrganization() const;
400     void SetOrganization(const PString & v);
401 
402     void GetProductInfo(OpalProductInfo & info) const;
403     void SetProductInfo(const PString & ua, const OpalProductInfo & info);
404 
405     PString GetWWWAuthenticate() const;
406     void SetWWWAuthenticate(const PString & v);
407 
408     PString GetSIPIfMatch() const;
409     void SetSIPIfMatch(const PString & v);
410 
411     PString GetSIPETag() const;
412     void SetSIPETag(const PString & v);
413 
414     void GetAlertInfo(PString & info, int & appearance);
415     void SetAlertInfo(const PString & info, int appearance);
416 
417     PString GetCallInfo() const;
418 
419     PString GetAllowEvents() const;
420     void SetAllowEvents(const PString & v);
421 
422     /** return the value of a header field parameter, empty if none
423      */
424     PString GetFieldParameter(
425       const PString & fieldName,    ///< Field name in dictionary
426       const PString & paramName,    ///< Field parameter name
427       const PString & defaultValue = PString::Empty()  ///< Default value for parameter
428     ) const { return ExtractFieldParameter((*this)(fieldName), paramName, defaultValue); }
429 
430     /** set the value for a header field parameter, replace the
431      *  current value, or add the parameter and its
432      *  value if not already present.
433      */
SetFieldParameter(const PString & fieldName,const PString & paramName,const PString & newValue)434     void SetFieldParameter(
435       const PString & fieldName,    ///< Field name in dictionary
436       const PString & paramName,    ///< Field parameter name
437       const PString & newValue      ///< New value for parameter
438     ) { SetAt(fieldName, InsertFieldParameter((*this)(fieldName), paramName, newValue)); }
439 
440     /** return the value of a header field parameter, empty if none
441      */
442     static PString ExtractFieldParameter(
443       const PString & fieldValue,   ///< Value of field string
444       const PString & paramName,    ///< Field parameter name
445       const PString & defaultValue = PString::Empty()  ///< Default value for parameter
446     );
447 
448     /** set the value for a header field parameter, replace the
449      *  current value, or add the parameter and its
450      *  value if not already present.
451      */
452     static PString InsertFieldParameter(
453       const PString & fieldValue,   ///< Value of field string
454       const PString & paramName,    ///< Field parameter name
455       const PString & newValue      ///< New value for parameter
456     );
457 
458   protected:
459     PStringSet GetTokenSet(const char * field) const;
460     void AddTokenSet(const char * field, const PString & token);
461     void SetTokenSet(const char * field, const PStringSet & tokens);
462 
463     /// Encode using compact form
464     bool compactForm;
465 };
466 
467 
468 /////////////////////////////////////////////////////////////////////////
469 // SIPAuthentication
470 
471 typedef PHTTPClientAuthentication SIPAuthentication;
472 
473 class SIPAuthenticator : public PHTTPClientAuthentication::AuthObject
474 {
475   public:
476     SIPAuthenticator(SIP_PDU & pdu);
477     virtual PMIMEInfo & GetMIME();
478     virtual PString GetURI();
479     virtual PString GetEntityBody();
480     virtual PString GetMethod();
481 
482   protected:
483     SIP_PDU & m_pdu;
484 };
485 
486 
487 
488 /////////////////////////////////////////////////////////////////////////
489 // SIP_PDU
490 
491 /** Session Initiation Protocol message.
492 	Each message contains a header, MIME lines and possibly SDP.
493 	Class provides methods for reading from and writing to transport.
494  */
495 
496 class SIP_PDU : public PSafeObject
497 {
498   PCLASSINFO(SIP_PDU, PSafeObject);
499   public:
500     enum Methods {
501       Method_INVITE,
502       Method_ACK,
503       Method_OPTIONS,
504       Method_BYE,
505       Method_CANCEL,
506       Method_REGISTER,
507       Method_SUBSCRIBE,
508       Method_NOTIFY,
509       Method_REFER,
510       Method_MESSAGE,
511       Method_INFO,
512       Method_PING,
513       Method_PUBLISH,
514       Method_PRACK,
515       NumMethods
516     };
517 
518     enum StatusCodes {
519       IllegalStatusCode,
520       Local_TransportError,
521       Local_BadTransportAddress,
522       Local_Timeout,
523 
524       Information_Trying                  = 100,
525       Information_Ringing                 = 180,
526       Information_CallForwarded           = 181,
527       Information_Queued                  = 182,
528       Information_Session_Progress        = 183,
529 
530       Successful_OK                       = 200,
531       Successful_Accepted		          = 202,
532 
533       Redirection_MultipleChoices         = 300,
534       Redirection_MovedPermanently        = 301,
535       Redirection_MovedTemporarily        = 302,
536       Redirection_UseProxy                = 305,
537       Redirection_AlternativeService      = 380,
538 
539       Failure_BadRequest                  = 400,
540       Failure_UnAuthorised                = 401,
541       Failure_PaymentRequired             = 402,
542       Failure_Forbidden                   = 403,
543       Failure_NotFound                    = 404,
544       Failure_MethodNotAllowed            = 405,
545       Failure_NotAcceptable               = 406,
546       Failure_ProxyAuthenticationRequired = 407,
547       Failure_RequestTimeout              = 408,
548       Failure_Conflict                    = 409,
549       Failure_Gone                        = 410,
550       Failure_LengthRequired              = 411,
551       Failure_RequestEntityTooLarge       = 413,
552       Failure_RequestURITooLong           = 414,
553       Failure_UnsupportedMediaType        = 415,
554       Failure_UnsupportedURIScheme        = 416,
555       Failure_BadExtension                = 420,
556       Failure_ExtensionRequired           = 421,
557       Failure_IntervalTooBrief            = 423,
558       Failure_TemporarilyUnavailable      = 480,
559       Failure_TransactionDoesNotExist     = 481,
560       Failure_LoopDetected                = 482,
561       Failure_TooManyHops                 = 483,
562       Failure_AddressIncomplete           = 484,
563       Failure_Ambiguous                   = 485,
564       Failure_BusyHere                    = 486,
565       Failure_RequestTerminated           = 487,
566       Failure_NotAcceptableHere           = 488,
567       Failure_BadEvent                    = 489,
568       Failure_RequestPending              = 491,
569       Failure_Undecipherable              = 493,
570 
571       Failure_InternalServerError         = 500,
572       Failure_NotImplemented              = 501,
573       Failure_BadGateway                  = 502,
574       Failure_ServiceUnavailable          = 503,
575       Failure_ServerTimeout               = 504,
576       Failure_SIPVersionNotSupported      = 505,
577       Failure_MessageTooLarge             = 513,
578 
579       GlobalFailure_BusyEverywhere        = 600,
580       GlobalFailure_Decline               = 603,
581       GlobalFailure_DoesNotExistAnywhere  = 604,
582       GlobalFailure_NotAcceptable         = 606,
583 
584       MaxStatusCode                       = 699
585     };
586 
587     static const char * GetStatusCodeDescription(int code);
588     friend ostream & operator<<(ostream & strm, StatusCodes status);
589 
590     SIP_PDU(
591       Methods method = SIP_PDU::NumMethods
592     );
593 
594     /** Construct a Response message
595         extra is passed as message body
596      */
597     SIP_PDU(
598       const SIP_PDU & request,
599       StatusCodes code,
600       const SDPSessionDescription * sdp = NULL
601     );
602 
603     SIP_PDU(const SIP_PDU &);
604     SIP_PDU & operator=(const SIP_PDU &);
605     ~SIP_PDU();
606 
607     void PrintOn(
608       ostream & strm
609     ) const;
610 
611     void InitialiseHeaders(
612       const SIPURL & dest,
613       const SIPURL & to,
614       const SIPURL & from,
615       const PString & callID,
616       unsigned cseq,
617       const PString & via
618     );
619     void InitialiseHeaders(
620       SIPDialogContext & dialog,
621       const PString & via = PString::Empty(),
622       unsigned cseq = 0
623     );
624     void InitialiseHeaders(
625       SIPConnection & connection,
626       const OpalTransport & transport,
627       unsigned cseq = 0
628     );
629     void InitialiseHeaders(
630       const SIP_PDU & request
631     );
632 
633     /**Add and populate Route header following the given routeSet.
634       If first route is strict, exchange with URI.
635       Returns true if routeSet.
636       */
637     bool SetRoute(const SIPURLList & routeSet);
638     bool SetRoute(const SIPURL & proxy);
639 
640     /**Set mime allow field to all supported methods.
641       */
642     void SetAllow(unsigned bitmask);
643 
644     /**Update the VIA field following RFC3261, 18.2.1 and RFC3581.
645       */
646     void AdjustVia(OpalTransport & transport);
647 
648     PString CreateVia(
649       SIPEndPoint & endpoint,
650       const OpalTransport & transport
651     );
652 
653     /**Read PDU from the specified transport.
654       */
655     SIP_PDU::StatusCodes Read(
656       OpalTransport & transport
657     );
658 
659     /**Write the PDU to the transport.
660       */
661     PBoolean Write(
662       OpalTransport & transport,
663       const OpalTransportAddress & remoteAddress = OpalTransportAddress(),
664       const PString & localInterface = PString::Empty()
665     );
666 
667     /**Write PDU as a response to a request.
668     */
669     bool SendResponse(
670       OpalTransport & transport,
671       StatusCodes code,
672       SIPEndPoint * endpoint = NULL
673     ) const;
674     bool SendResponse(
675       OpalTransport & transport,
676       SIP_PDU & response,
677       SIPEndPoint * endpoint = NULL
678     ) const;
679 
680     /** Construct the PDU string to output.
681         Returns the total length of the PDU.
682       */
683     PString Build();
684 
685     PString GetTransactionID() const;
686 
GetMethod()687     Methods GetMethod() const                { return m_method; }
GetStatusCode()688     StatusCodes GetStatusCode () const       { return m_statusCode; }
SetStatusCode(StatusCodes c)689     void SetStatusCode (StatusCodes c)       { m_statusCode = c; }
GetURI()690     const SIPURL & GetURI() const            { return m_uri; }
SetURI(const SIPURL & newuri)691     void SetURI(const SIPURL & newuri)       { m_uri = newuri; }
GetVersionMajor()692     unsigned GetVersionMajor() const         { return m_versionMajor; }
GetVersionMinor()693     unsigned GetVersionMinor() const         { return m_versionMinor; }
694     void SetCSeq(unsigned cseq);
GetEntityBody()695     const PString & GetEntityBody() const    { return m_entityBody; }
SetEntityBody(const PString & body)696     void SetEntityBody(const PString & body) { m_entityBody = body; }
697     void SetEntityBody();
GetInfo()698     const PString & GetInfo() const          { return m_info; }
SetInfo(const PString & info)699     void SetInfo(const PString & info)       { m_info = info; }
GetMIME()700     const SIPMIMEInfo & GetMIME() const      { return m_mime; }
GetMIME()701           SIPMIMEInfo & GetMIME()            { return m_mime; }
702     SDPSessionDescription * GetSDP(const OpalMediaFormatList & masterList);
703     void SetSDP(SDPSessionDescription * sdp);
704 
705   protected:
706     Methods     m_method;                 // Request type, ==NumMethods for Response
707     StatusCodes m_statusCode;
708     SIPURL      m_uri;                    // display name & URI, no tag
709     unsigned    m_versionMajor;
710     unsigned    m_versionMinor;
711     PString     m_info;
712     SIPMIMEInfo m_mime;
713     PString     m_entityBody;
714 
715     SDPSessionDescription * m_SDP;
716 
717     mutable PString m_transactionID;
718 };
719 
720 
721 PQUEUE(SIP_PDU_Queue, SIP_PDU);
722 
723 
724 #if PTRACING
725 ostream & operator<<(ostream & strm, SIP_PDU::Methods method);
726 #endif
727 
728 
729 /////////////////////////////////////////////////////////////////////////
730 // SIPDialogContext
731 
732 /** Session Initiation Protocol dialog context information.
733   */
734 class SIPDialogContext
735 {
736   public:
737     SIPDialogContext();
738     SIPDialogContext(const SIPMIMEInfo & mime);
739 
740     PString AsString() const;
741     bool FromString(
742       const PString & str
743     );
744 
GetCallID()745     const PString & GetCallID() const { return m_callId; }
SetCallID(const PString & id)746     void SetCallID(const PString & id) { m_callId = id; }
747 
GetRequestURI()748     const SIPURL & GetRequestURI() const { return m_requestURI; }
SetRequestURI(const SIPURL & url)749     void SetRequestURI(const SIPURL & url) { m_requestURI = url; }
750 
GetLocalTag()751     const PString & GetLocalTag() const { return m_localTag; }
SetLocalTag(const PString & tag)752     void SetLocalTag(const PString & tag) { m_localTag = tag; }
753 
GetLocalURI()754     const SIPURL & GetLocalURI() const { return m_localURI; }
755     void SetLocalURI(const SIPURL & url);
756 
GetRemoteTag()757     const PString & GetRemoteTag() const { return m_remoteTag; }
SetRemoteTag(const PString & tag)758     void SetRemoteTag(const PString & tag) { m_remoteTag = tag; }
759 
GetRemoteURI()760     const SIPURL & GetRemoteURI() const { return m_remoteURI; }
761     void SetRemoteURI(const SIPURL & url);
762 
GetRouteSet()763     const SIPURLList & GetRouteSet() const { return m_routeSet; }
SetRouteSet(const PString & str)764     void SetRouteSet(const PString & str) { m_routeSet.FromString(str); }
765 
GetProxy()766     const SIPURL & GetProxy() const { return m_proxy; }
767     void SetProxy(const SIPURL & proxy, bool addToRouteSet);
768 
769     void Update(OpalTransport & transport, const SIP_PDU & response);
770 
771     unsigned GetNextCSeq();
IncrementCSeq(unsigned inc)772     void IncrementCSeq(unsigned inc) { m_lastSentCSeq += inc; }
773 
774     bool IsDuplicateCSeq(unsigned sequenceNumber);
775 
IsEstablished()776     bool IsEstablished() const
777     {
778       return !m_callId.IsEmpty() &&
779              !m_requestURI.IsEmpty() &&
780              !m_localTag.IsEmpty() &&
781              !m_remoteTag.IsEmpty();
782     }
783 
784     OpalTransportAddress GetRemoteTransportAddress() const;
785 
SetForking(bool f)786     void SetForking(bool f) { m_forking = f; }
787 
788   protected:
789     PString     m_callId;
790     SIPURL      m_requestURI;
791     SIPURL      m_localURI;
792     PString     m_localTag;
793     SIPURL      m_remoteURI;
794     PString     m_remoteTag;
795     SIPURLList  m_routeSet;
796     unsigned    m_lastSentCSeq;
797     unsigned    m_lastReceivedCSeq;
798     OpalTransportAddress m_externalTransportAddress;
799     bool        m_forking;
800     SIPURL      m_proxy;
801 };
802 
803 
804 /////////////////////////////////////////////////////////////////////////
805 
806 struct SIPParameters
807 {
808   SIPParameters(
809     const PString & aor = PString::Empty(),
810     const PString & remote = PString::Empty()
811   );
812 
813   void Normalise(
814     const PString & defaultUser,
815     const PTimeInterval & defaultExpire
816   );
817 
818   PCaselessString m_remoteAddress;
819   PCaselessString m_localAddress;
820   PCaselessString m_proxyAddress;
821   PCaselessString m_addressOfRecord;
822   PCaselessString m_contactAddress;
823   PCaselessString m_interface;
824   SIPMIMEInfo     m_mime;
825   PString         m_authID;
826   PString         m_password;
827   PString         m_realm;
828   unsigned        m_expire;
829   unsigned        m_restoreTime;
830   PTimeInterval   m_minRetryTime;
831   PTimeInterval   m_maxRetryTime;
832   void          * m_userData;
833 };
834 
835 
836 #if PTRACING
837 ostream & operator<<(ostream & strm, const SIPParameters & params);
838 #endif
839 
840 
841 /////////////////////////////////////////////////////////////////////////
842 // SIPTransaction
843 
844 /** Session Initiation Protocol transaction.
845     A transaction is a stateful independent entity that provides services to
846     a connection (Transaction User). Transactions are contained within
847     connections.
848     A client transaction handles sending a request and receiving its
849     responses.
850     A server transaction handles sending responses to a received request.
851     In either case the SIP_PDU ancestor is the sent or received request.
852  */
853 
854 class SIPTransaction : public SIP_PDU
855 {
856     PCLASSINFO(SIPTransaction, SIP_PDU);
857   public:
858     SIPTransaction(
859       Methods method,
860       SIPEndPoint   & endpoint,
861       OpalTransport & transport
862     );
863     /** Construct a transaction for requests in a dialog.
864      *  The transport is used to determine the local address
865      */
866     SIPTransaction(
867       Methods method,
868       SIPConnection & connection
869     );
870     ~SIPTransaction();
871 
872     /* Under some circumstances a new transaction with all the same parameters
873        but different ID needs to be created, e.g. when get authentication error. */
874     virtual SIPTransaction * CreateDuplicate() const = 0;
875 
876     PBoolean Start();
IsTrying()877     bool IsTrying()     const { return m_state == Trying; }
IsProceeding()878     bool IsProceeding() const { return m_state == Proceeding; }
IsInProgress()879     bool IsInProgress() const { return m_state == Trying || m_state == Proceeding; }
IsFailed()880     bool IsFailed()     const { return m_state > Terminated_Success; }
IsCompleted()881     bool IsCompleted()  const { return m_state >= Completed; }
IsCanceled()882     bool IsCanceled()   const { return m_state == Cancelling || m_state == Terminated_Cancelled || m_state == Terminated_Aborted; }
IsTerminated()883     bool IsTerminated() const { return m_state >= Terminated_Success; }
884 
885     void WaitForCompletion();
886     PBoolean Cancel();
887     void Abort();
888 
889     virtual PBoolean OnReceivedResponse(SIP_PDU & response);
890     virtual PBoolean OnCompleted(SIP_PDU & response);
891 
GetTransport()892     OpalTransport & GetTransport()  const { return m_transport; }
GetConnection()893     SIPConnection * GetConnection() const { return m_connection; }
GetInterface()894     PString         GetInterface()  const { return m_localInterface; }
SetInterface(const PString & localIf)895     void            SetInterface(const PString & localIf)  { m_localInterface = localIf; }
896 
897     static PString GenerateCallID();
898 
899   protected:
900     bool SendPDU(SIP_PDU & pdu);
901     bool ResendCANCEL();
902     void SetParameters(const SIPParameters & params);
903 
904     PDECLARE_NOTIFIER(PTimer, SIPTransaction, OnRetry);
905     PDECLARE_NOTIFIER(PTimer, SIPTransaction, OnTimeout);
906 
907     enum States {
908       NotStarted,
909       Trying,
910       Proceeding,
911       Cancelling,
912       Completed,
913       Terminated_Success,
914       Terminated_Timeout,
915       Terminated_RetriesExceeded,
916       Terminated_TransportError,
917       Terminated_Cancelled,
918       Terminated_Aborted,
919       NumStates
920     };
921     virtual void SetTerminated(States newState);
922 
923     SIPEndPoint           & m_endpoint;
924     OpalTransport         & m_transport;
925     PSafePtr<SIPConnection> m_connection;
926     PTimeInterval           m_retryTimeoutMin;
927     PTimeInterval           m_retryTimeoutMax;
928 
929     States     m_state;
930     unsigned   m_retry;
931     PTimer     m_retryTimer;
932     PTimer     m_completionTimer;
933     PSyncPoint m_completed;
934 
935     PString              m_localInterface;
936     OpalTransportAddress m_remoteAddress;
937 };
938 
939 
940 #define OPAL_PROXY_PARAM     "OPAL-proxy"
941 #define OPAL_LOCAL_ID_PARAM  "OPAL-local-id"
942 #define OPAL_INTERFACE_PARAM "OPAL-interface"
943 
944 
945 /////////////////////////////////////////////////////////////////////////
946 // SIPResponse
947 
948 /** When we receive a command, we need a transaction to send repeated responses.
949  */
950 class SIPResponse : public SIPTransaction
951 {
952     PCLASSINFO(SIPResponse, SIPTransaction);
953   public:
954     SIPResponse(
955       SIPEndPoint   & endpoint,
956       StatusCodes code
957     );
958 
959     virtual SIPTransaction * CreateDuplicate() const;
960 
961     bool Send(OpalTransport & transport, const SIP_PDU & command);
962 };
963 
964 
965 /////////////////////////////////////////////////////////////////////////
966 // SIPInvite
967 
968 /** Session Initiation Protocol transaction for INVITE
969     INVITE implements a three-way handshake to handle the human input and
970     extended duration of the transaction.
971  */
972 
973 class SIPInvite : public SIPTransaction
974 {
975     PCLASSINFO(SIPInvite, SIPTransaction);
976   public:
977     SIPInvite(
978       SIPConnection & connection,
979       const OpalRTPSessionManager & sm
980     );
981 
982     virtual SIPTransaction * CreateDuplicate() const;
983 
984     virtual PBoolean OnReceivedResponse(SIP_PDU & response);
985 
GetSessionManager()986     const OpalRTPSessionManager & GetSessionManager() const { return m_rtpSessions; }
GetSessionManager()987           OpalRTPSessionManager & GetSessionManager()       { return m_rtpSessions; }
988 
989   protected:
990     OpalRTPSessionManager m_rtpSessions;
991 };
992 
993 
994 /////////////////////////////////////////////////////////////////////////
995 
996 /* This is the ACK request sent when receiving a response to an outgoing
997  * INVITE.
998  */
999 class SIPAck : public SIP_PDU
1000 {
1001     PCLASSINFO(SIPAck, SIP_PDU);
1002   public:
1003     SIPAck(
1004       SIPTransaction & invite,
1005       SIP_PDU & response
1006     );
1007 
1008     virtual SIPTransaction * CreateDuplicate() const;
1009 };
1010 
1011 
1012 /////////////////////////////////////////////////////////////////////////
1013 
1014 /* This is a BYE request
1015  */
1016 class SIPBye : public SIPTransaction
1017 {
1018     PCLASSINFO(SIPBye, SIPTransaction);
1019 
1020   public:
1021     SIPBye(
1022       SIPEndPoint & ep,
1023       OpalTransport & trans,
1024       SIPDialogContext dialog
1025     );
1026     SIPBye(
1027       SIPConnection & conn
1028     );
1029 
1030     virtual SIPTransaction * CreateDuplicate() const;
1031 };
1032 
1033 
1034 /////////////////////////////////////////////////////////////////////////
1035 
1036 class SIPRegister : public SIPTransaction
1037 {
1038     PCLASSINFO(SIPRegister, SIPTransaction);
1039   public:
1040     enum CompatibilityModes {
1041       e_FullyCompliant,                 /**< Registrar is fully compliant, we will register
1042                                              all listeners of all types (e.g. sip, sips etc)
1043                                              in the Contact field. */
1044       e_CannotRegisterMultipleContacts, /**< Registrar refuses to register more than one
1045                                              contact field. Correct behaviour is to return
1046                                              a contact with the fields it can accept in
1047                                              the 200 OK */
1048       e_CannotRegisterPrivateContacts,  /**< Registrar refuses to register any RFC
1049                                              contact field. Correct behaviour is to return
1050                                              a contact with the fields it can accept in
1051                                              the 200 OK */
1052       e_HasApplicationLayerGateway      /**< Router has Application Layer Gateway code that
1053                                              is doing address transations, so we do not try
1054                                              to do it ourselves as well or it goes horribly
1055                                              wrong. */
1056     };
1057 
1058     /// Registrar parameters
1059     struct Params : public SIPParameters {
ParamsParams1060       Params()
1061         : m_registrarAddress(m_remoteAddress)
1062         , m_compatibility(SIPRegister::e_FullyCompliant)
1063       { }
1064 
ParamsParams1065       Params(const Params & param)
1066         : SIPParameters(param)
1067         , m_registrarAddress(m_remoteAddress)
1068         , m_compatibility(param.m_compatibility)
1069       { }
1070 
1071       PCaselessString  & m_registrarAddress; // For backward compatibility
1072       CompatibilityModes m_compatibility;
1073     };
1074 
1075     SIPRegister(
1076       SIPEndPoint   & endpoint,
1077       OpalTransport & transport,
1078       const PString & callId,
1079       unsigned cseq,
1080       const Params & params
1081     );
1082 
1083     virtual SIPTransaction * CreateDuplicate() const;
1084 };
1085 
1086 
1087 #if PTRACING
1088 ostream & operator<<(ostream & strm, SIPRegister::CompatibilityModes mode);
1089 ostream & operator<<(ostream & strm, const SIPRegister::Params & params);
1090 #endif
1091 
1092 
1093 /////////////////////////////////////////////////////////////////////////
1094 
1095 class SIPSubscribe : public SIPTransaction
1096 {
1097     PCLASSINFO(SIPSubscribe, SIPTransaction);
1098   public:
1099     /** Valid types for an event package
1100      */
1101     enum PredefinedPackages {
1102       MessageSummary,
1103       Presence,
1104       Dialog,
1105 
1106       NumPredefinedPackages,
1107 
1108       Watcher = 0x8000,
1109 
1110       MessageSummaryWatcher = Watcher|MessageSummary,
1111       PresenceWatcher       = Watcher|Presence,
1112       DialogWatcher         = Watcher|Dialog,
1113 
1114       PackageMask = Watcher-1
1115     };
1116     friend PredefinedPackages operator|(PredefinedPackages p1, PredefinedPackages p2) { return (PredefinedPackages)((int)p1|(int)p2); }
1117 
1118     class EventPackage : public PCaselessString
1119     {
1120       PCLASSINFO(EventPackage, PCaselessString);
1121       public:
1122         EventPackage(PredefinedPackages = NumPredefinedPackages);
EventPackage(const PString & str)1123         explicit EventPackage(const PString & str) : PCaselessString(str) { }
EventPackage(const char * str)1124         explicit EventPackage(const char   *  str) : PCaselessString(str) { }
1125 
1126         EventPackage & operator=(PredefinedPackages pkg);
1127         EventPackage & operator=(const PString & str) { PCaselessString::operator=(str); return *this; }
1128         EventPackage & operator=(const char   *  str) { PCaselessString::operator=(str); return *this; }
1129 
1130         bool operator==(PredefinedPackages pkg) const { return Compare(EventPackage(pkg)) == EqualTo; }
1131         bool operator==(const PString & str) const { return Compare(str) == EqualTo; }
1132         bool operator==(const char * cstr) const { return InternalCompare(0, P_MAX_INDEX, cstr) == EqualTo; }
1133         virtual Comparison InternalCompare(PINDEX offset, PINDEX length, const char * cstr) const;
1134 
1135         bool IsWatcher() const;
1136     };
1137 
1138     /** Information provided on the subscription status. */
1139     struct SubscriptionStatus {
1140       SIPSubscribeHandler * m_handler;           ///< Handler for subscription
1141       PString               m_addressofRecord;   ///< Address of record for registration
1142       bool                  m_wasSubscribing;    ///< Was registering or unregistering
1143       bool                  m_reSubscribing;     ///< Was a registration refresh
1144       SIP_PDU::StatusCodes  m_reason;            ///< Reason for status change
1145       OpalProductInfo       m_productInfo;       ///< Server product info from registrar if available.
1146       void                * m_userData;          ///< User data corresponding to this registration
1147     };
1148 
1149     struct NotifyCallbackInfo {
1150       NotifyCallbackInfo(
1151         SIPEndPoint & ep,
1152         OpalTransport & trans,
1153         SIP_PDU & notify,
1154         SIP_PDU & response
1155       );
1156 
1157       bool SendResponse(
1158         SIP_PDU::StatusCodes status,
1159         const char * extra = NULL
1160       );
1161 
1162       SIPEndPoint   & m_endpoint;
1163       OpalTransport & m_transport;
1164       SIP_PDU       & m_notify;
1165       SIP_PDU       & m_response;
1166       bool            m_sendResponse;
1167     };
1168 
1169     struct Params : public SIPParameters
1170     {
1171       Params(PredefinedPackages pkg = NumPredefinedPackages)
m_agentAddressParams1172         : m_agentAddress(m_remoteAddress)
1173         , m_eventPackage(pkg)
1174         , m_eventList(false)
1175       { }
1176 
ParamsParams1177       Params(const Params & param)
1178         : SIPParameters(param)
1179         , m_agentAddress(m_remoteAddress)
1180         , m_eventPackage(param.m_eventPackage)
1181         , m_eventList(param.m_eventList)
1182         , m_contentType(param.m_contentType)
1183         , m_onSubcribeStatus(param.m_onSubcribeStatus)
1184         , m_onNotify(param.m_onNotify)
1185       { }
1186 
1187       PCaselessString & m_agentAddress; // For backward compatibility
1188       EventPackage      m_eventPackage;
1189       bool              m_eventList;    // Enable RFC4662
1190       PCaselessString   m_contentType;  // May be \n separated list of types
1191 
1192       PNotifierTemplate<const SubscriptionStatus &> m_onSubcribeStatus;
1193       PNotifierTemplate<NotifyCallbackInfo &> m_onNotify;
1194     };
1195 
1196     SIPSubscribe(
1197         SIPEndPoint & ep,
1198         OpalTransport & trans,
1199         SIPDialogContext & dialog,
1200         const Params & params
1201     );
1202 
1203     virtual SIPTransaction * CreateDuplicate() const;
1204 };
1205 
1206 
1207 #if PTRACING
1208 ostream & operator<<(ostream & strm, const SIPSubscribe::Params & params);
1209 #endif
1210 
1211 
1212 typedef SIPSubscribe::EventPackage SIPEventPackage;
1213 
1214 
1215 /////////////////////////////////////////////////////////////////////////
1216 
1217 class SIPHandler;
1218 
1219 class SIPEventPackageHandler
1220 {
1221 public:
~SIPEventPackageHandler()1222   virtual ~SIPEventPackageHandler() { }
1223   virtual PCaselessString GetContentType() const = 0;
1224   virtual bool ValidateContentType(const PString & type, const SIPMIMEInfo & mime);
1225   virtual bool OnReceivedNOTIFY(SIPHandler & handler, SIP_PDU & request) = 0;
OnSendNOTIFY(SIPHandler &,const PObject *)1226   virtual PString OnSendNOTIFY(SIPHandler & /*handler*/, const PObject * /*body*/) { return PString::Empty(); }
1227 };
1228 
1229 
1230 typedef PFactory<SIPEventPackageHandler, SIPEventPackage> SIPEventPackageFactory;
1231 
1232 
1233 /////////////////////////////////////////////////////////////////////////
1234 
1235 class SIPNotify : public SIPTransaction
1236 {
1237     PCLASSINFO(SIPNotify, SIPTransaction);
1238   public:
1239     SIPNotify(
1240         SIPEndPoint & ep,
1241         OpalTransport & trans,
1242         SIPDialogContext & dialog,
1243         const SIPEventPackage & eventPackage,
1244         const PString & state,
1245         const PString & body
1246     );
1247 
1248     virtual SIPTransaction * CreateDuplicate() const;
1249 };
1250 
1251 
1252 /////////////////////////////////////////////////////////////////////////
1253 
1254 class SIPPublish : public SIPTransaction
1255 {
1256     PCLASSINFO(SIPPublish, SIPTransaction);
1257   public:
1258     SIPPublish(
1259       SIPEndPoint & ep,
1260       OpalTransport & trans,
1261       const PString & id,
1262       const PString & sipIfMatch,
1263       const SIPSubscribe::Params & params,
1264       const PString & body
1265     );
1266 
1267     virtual SIPTransaction * CreateDuplicate() const;
1268 };
1269 
1270 
1271 /////////////////////////////////////////////////////////////////////////
1272 
1273 class SIPRefer : public SIPTransaction
1274 {
1275   PCLASSINFO(SIPRefer, SIPTransaction);
1276   public:
1277     SIPRefer(
1278       SIPConnection & connection,
1279       const SIPURL & referTo,
1280       const SIPURL & referred_by,
1281       bool referSub
1282     );
1283 
1284     virtual SIPTransaction * CreateDuplicate() const;
1285 };
1286 
1287 
1288 /////////////////////////////////////////////////////////////////////////
1289 
1290 /* This is not a generic NOTIFY PDU, but the minimal one
1291  * that gets sent when receiving a REFER
1292  */
1293 class SIPReferNotify : public SIPTransaction
1294 {
1295     PCLASSINFO(SIPReferNotify, SIPTransaction);
1296   public:
1297     SIPReferNotify(
1298       SIPConnection & connection,
1299       StatusCodes code
1300     );
1301 
1302     virtual SIPTransaction * CreateDuplicate() const;
1303 };
1304 
1305 
1306 /////////////////////////////////////////////////////////////////////////
1307 
1308 /* This is a MESSAGE PDU, with a body
1309  */
1310 class SIPMessage : public SIPTransaction
1311 {
1312   PCLASSINFO(SIPMessage, SIPTransaction);
1313   public:
1314     struct Params : public SIPParameters
1315     {
ParamsParams1316       Params()
1317         : m_contentType("text/plain;charset=UTF-8")
1318       {
1319         m_expire = 5000;
1320       }
1321 
1322       PCaselessString             m_contentType;
1323       PString                     m_id;
1324       PString                     m_body;
1325       PAtomicInteger::IntegerType m_messageId;
1326     };
1327 
1328     SIPMessage(
1329       SIPEndPoint & ep,
1330       OpalTransport & trans,
1331       const Params & params
1332     );
1333     SIPMessage(
1334       SIPConnection & connection,
1335       const Params & params
1336     );
1337 
1338     virtual SIPTransaction * CreateDuplicate() const;
1339 
GetLocalAddress()1340     const SIPURL & GetLocalAddress() const { return m_localAddress; }
1341 
1342   private:
1343     void Construct(const Params & params);
1344 
1345     SIPURL m_localAddress;
1346 };
1347 
1348 
1349 /////////////////////////////////////////////////////////////////////////
1350 
1351 /* This is an OPTIONS request
1352  */
1353 class SIPOptions : public SIPTransaction
1354 {
1355     PCLASSINFO(SIPOptions, SIPTransaction);
1356 
1357   public:
1358     struct Params : public SIPParameters
1359     {
ParamsParams1360       Params()
1361         : m_acceptContent("application/sdp, application/media_control+xml, application/dtmf, application/dtmf-relay")
1362       {
1363       }
1364 
1365       PCaselessString m_acceptContent;
1366       PCaselessString m_contentType;
1367       PString         m_body;
1368     };
1369 
1370     SIPOptions(
1371       SIPEndPoint & ep,
1372       OpalTransport & trans,
1373       const PString & id,
1374       const Params & params
1375     );
1376     SIPOptions(
1377       SIPConnection & conn,
1378       const Params & params
1379     );
1380 
1381     virtual SIPTransaction * CreateDuplicate() const;
1382 
1383   protected:
1384     void Construct(const Params & params);
1385 };
1386 
1387 
1388 /////////////////////////////////////////////////////////////////////////
1389 
1390 /* This is an INFO request
1391  */
1392 class SIPInfo : public SIPTransaction
1393 {
1394     PCLASSINFO(SIPInfo, SIPTransaction);
1395 
1396   public:
1397     struct Params
1398     {
1399       Params(const PString & contentType = PString::Empty(),
1400              const PString & body = PString::Empty())
m_contentTypeParams1401         : m_contentType(contentType)
1402         , m_body(body)
1403       {
1404       }
1405 
1406       PCaselessString m_contentType;
1407       PString         m_body;
1408     };
1409 
1410     SIPInfo(
1411       SIPConnection & conn,
1412       const Params & params
1413     );
1414 
1415     virtual SIPTransaction * CreateDuplicate() const;
1416 };
1417 
1418 
1419 /////////////////////////////////////////////////////////////////////////
1420 
1421 /* This is a PING PDU, with a body
1422  */
1423 class SIPPing : public SIPTransaction
1424 {
1425   PCLASSINFO(SIPPing, SIPTransaction);
1426 
1427   public:
1428     SIPPing(
1429       SIPEndPoint & ep,
1430       OpalTransport & trans,
1431       const SIPURL & address
1432     );
1433 
1434     virtual SIPTransaction * CreateDuplicate() const;
1435 };
1436 
1437 
1438 /////////////////////////////////////////////////////////////////////////
1439 
1440 /* This is a PRACK PDU
1441  */
1442 class SIPPrack : public SIPTransaction
1443 {
1444   PCLASSINFO(SIPPrack, SIPTransaction);
1445 
1446   public:
1447     SIPPrack(
1448       SIPConnection & conn,
1449       const PString & rack
1450     );
1451 
1452     virtual SIPTransaction * CreateDuplicate() const;
1453 };
1454 
1455 
1456 #endif // OPAL_SIP
1457 
1458 #endif // OPAL_SIP_SIPPDU_H
1459 
1460 
1461 // End of File ///////////////////////////////////////////////////////////////
1462