/src/resiprocate/resip/stack/SipMessage.hxx
Line | Count | Source |
1 | | #if !defined(RESIP_SIPMESSAGE_HXX) |
2 | | #define RESIP_SIPMESSAGE_HXX |
3 | | |
4 | | #include <sys/types.h> |
5 | | |
6 | | #include <list> |
7 | | #include <vector> |
8 | | #include <utility> |
9 | | #include <memory> |
10 | | #include <iterator> |
11 | | #include <type_traits> |
12 | | |
13 | | #include "resip/stack/Contents.hxx" |
14 | | #include "resip/stack/Headers.hxx" |
15 | | #include "resip/stack/TransactionMessage.hxx" |
16 | | #include "resip/stack/ParserContainer.hxx" |
17 | | #include "resip/stack/ParserCategories.hxx" |
18 | | #include "resip/stack/SecurityAttributes.hxx" |
19 | | #include "resip/stack/Tuple.hxx" |
20 | | #include "resip/stack/Uri.hxx" |
21 | | #include "resip/stack/MessageDecorator.hxx" |
22 | | #include "resip/stack/Cookie.hxx" |
23 | | #include "resip/stack/WsCookieContext.hxx" |
24 | | #include "rutil/BaseException.hxx" |
25 | | #include "rutil/Data.hxx" |
26 | | #include "rutil/DinkyPool.hxx" |
27 | | #include "rutil/StlPoolAllocator.hxx" |
28 | | #include "rutil/Timer.hxx" |
29 | | #include "rutil/HeapInstanceCounter.hxx" |
30 | | |
31 | | namespace resip |
32 | | { |
33 | | |
34 | | class Contents; |
35 | | class ExtensionHeader; |
36 | | class SecurityAttributes; |
37 | | |
38 | | /** |
39 | | @ingroup resip_crit |
40 | | @ingroup message_passing_tu |
41 | | @brief Represents a SIP message. |
42 | | |
43 | | This is the class that your app will spend the most time working with. This |
44 | | is because, in the UA core/Transaction User architecture, the vast majority |
45 | | of interaction is carried out through SIP messaging. |
46 | | |
47 | | When you get a SipMessage, generally the first thing you want to know is |
48 | | whether it is a request or a response. This is done by calling |
49 | | SipMessage::isRequest() or SipMessage::isResponse(). |
50 | | |
51 | | Next, it is usually important to determine what the SIP method of the message |
52 | | is. This is done by calling SipMessage::method() (this is a convenience |
53 | | function that checks the method of the Request-Line if the message is a |
54 | | request, or the method of the CSeq if a response). |
55 | | |
56 | | At this point, it may become useful to examine the start-line of the message. |
57 | | |
58 | | If the message is a request, you can get the Request-Line (represented by a |
59 | | RequestLine&) by calling SipMessage::header(const RequestLineType&) |
60 | | @code |
61 | | RequestLine& rLine = sip.header(h_RequestLine); |
62 | | @endcode |
63 | | |
64 | | If the message is a response, you can get the Status-Line (represented by a StatusLine&) by calling SipMessage::header(const StatusLineType&) |
65 | | @code |
66 | | StatusLine& sLine = sip.header(h_StatusLine); |
67 | | @endcode |
68 | | |
69 | | From here, examination of the various headers is in order. The way the |
70 | | underlying code works is very complicated, but fortunately relatively |
71 | | painless to use. For each header type, there is a subclass of HeaderBase, and |
72 | | a SipMessage::header() function that takes a reference to this subclass. On |
73 | | top of this, there is a static instance of each of these subclasses. Examples |
74 | | include h_To, h_From, h_CSeq, h_CallId, h_Routes, h_Contacts, h_RecordRoutes, |
75 | | etc. |
76 | | |
77 | | @code |
78 | | NameAddr& to = sip.header(h_To); |
79 | | NameAddr& from = sip.header(h_From); |
80 | | CSeqCategory& cseq = sip.header(h_CSeq); |
81 | | CallId& callId = sip.header(h_CallId); |
82 | | ParserContainer<NameAddr>& routes = sip.header(h_Routes); |
83 | | ParserContainer<NameAddr>& contacts = sip.header(h_Contacts); |
84 | | ParserContainer<NameAddr>& rRoutes = sip.header(h_RecordRoutes); |
85 | | @endcode |
86 | | |
87 | | Generally speaking, the access token is named in a predictable fashion; all |
88 | | non-alphanumeric characters are omitted, the first letter of each word is |
89 | | capitalized, and the name is pluralized if the header is multi-valued (since |
90 | | this stuff is all macro-generated, sometimes this pluralization isn't quite |
91 | | right; h_AllowEventss, h_PAssertedIdentitys). |
92 | | |
93 | | When accessing a single-value header, you need to check whether it |
94 | | exists first (unless you want it to be created implicitly). Also, since all |
95 | | header field values are lazily parsed (see LazyParser), you'll want to make |
96 | | sure it is well-formed before attempting to access any portion of it. |
97 | | |
98 | | @code |
99 | | if(sip.exists(h_Event)) |
100 | | { |
101 | | Token& event = sip.header(h_Event); |
102 | | if(event.isWellFormed()) |
103 | | { |
104 | | // do stuff with event. |
105 | | } |
106 | | else |
107 | | { |
108 | | // complain bitterly |
109 | | } |
110 | | } |
111 | | @endcode |
112 | | |
113 | | When accessing a multi-value header, it is important to keep in mind that |
114 | | it can be empty, even if it exists (for example, "Supported: " has a meaning |
115 | | that is distinct from the lack of a Supported header). |
116 | | |
117 | | @code |
118 | | if(sip.exists(h_Contacts)) |
119 | | { |
120 | | ParserContainer<NameAddr>& contacts = sip.header(h_Contacts); |
121 | | if(!contacts.empty()) |
122 | | { |
123 | | NameAddr& frontContact = contacts.front(); |
124 | | if(frontContact.isWellFormed()) |
125 | | { |
126 | | // do stuff with frontContact |
127 | | } |
128 | | else |
129 | | { |
130 | | // complain bitterly |
131 | | } |
132 | | } |
133 | | else |
134 | | { |
135 | | // complain bitterly |
136 | | } |
137 | | } |
138 | | @endcode |
139 | | |
140 | | In some cases, you will need to access header-types that are not natively |
141 | | supported by the stack (ie, don't have an access-token). ExtensionHeader will |
142 | | allow you to construct an access-token at runtime that will retrieve the |
143 | | header field value as a ParserContainer<StringCategory>. Here's an example: |
144 | | |
145 | | @code |
146 | | // We need to access the FooBar header field value here. |
147 | | static ExtensionHeader h_FooBar("FooBar"); |
148 | | if(sip.exists(h_FooBar)) |
149 | | { |
150 | | ParserContainer<StringCategory>& fooBars = sip.header(h_FooBar); |
151 | | } |
152 | | @endcode |
153 | | |
154 | | */ |
155 | | class SipMessage : public TransactionMessage |
156 | | { |
157 | | public: |
158 | | RESIP_HeapCount(SipMessage); |
159 | | #ifndef __SUNPRO_CC |
160 | | typedef std::list< std::pair<Data, HeaderFieldValueList*>, StlPoolAllocator<std::pair<Data, HeaderFieldValueList*>, PoolBase > > UnknownHeaders; |
161 | | #else |
162 | | typedef std::list< std::pair<Data, HeaderFieldValueList*> > UnknownHeaders; |
163 | | #endif |
164 | | |
165 | | /** |
166 | | * @brief List of known SIP headers, searchable by header type. |
167 | | * |
168 | | * This container provides access to headers of the SIP message that are known to libresiprocate. |
169 | | * The headers can be searched by `Headers::Type` enum values and iterated over. The list of headers |
170 | | * is unordered, and any modifications of the container may invalidate iterators, pointers and references |
171 | | * into the container. The container does not own the `HeaderFieldValueList` objects, which must be |
172 | | * explicitly freed on removal (which is handled by `SipMessage`). |
173 | | * |
174 | | * Elements of the container can be in an "unused" state, which is when the element was removed but |
175 | | * not disposed of. "Unused" elements do not participate in the publicly visible set of elements observed |
176 | | * by users (e.g. they are not found by searching or exposed during iteration). "Unused" elements can be |
177 | | * reused if the user attempts to insert an element with the matching header type. After that, the reused |
178 | | * element becomes publicly accessible again. |
179 | | */ |
180 | | class KnownHeaders |
181 | | { |
182 | | private: |
183 | | /// Small index type that is used to map header type ids onto vector elements |
184 | | using HeaderIndex = unsigned char; |
185 | | /// Header index value that indicates invalid index |
186 | | static constexpr HeaderIndex InvalidHeaderIndex = static_cast<HeaderIndex>(-1); |
187 | | static_assert(Headers::MAX_HEADERS <= InvalidHeaderIndex, "HeaderIndex type is too small to cover all SIP header types"); |
188 | | |
189 | | public: |
190 | | /// Publicly accessible information about a header |
191 | | class HeaderInfo |
192 | | { |
193 | | friend class KnownHeaders; |
194 | | |
195 | | private: |
196 | | /// Pointer to header values |
197 | | HeaderFieldValueList* mValues; |
198 | | /// Header type. If `Headers::UNKNOWN`, indicates that this entry is in the "unused" state. |
199 | | Headers::Type mType; |
200 | | |
201 | | public: |
202 | 0 | constexpr HeaderInfo() noexcept : mValues(nullptr), mType(Headers::UNKNOWN) {} |
203 | 1.25k | explicit constexpr HeaderInfo(Headers::Type type, HeaderFieldValueList* values = nullptr) noexcept : mValues(values), mType(type) {} |
204 | | |
205 | | /// Returns header type |
206 | 682k | Headers::Type getType() const noexcept { return mType; } |
207 | | |
208 | | /// Returns header values |
209 | 679k | HeaderFieldValueList* getValues() const noexcept { return mValues; } |
210 | | /// Sets header values |
211 | 1.25k | void setValues(HeaderFieldValueList* values) noexcept { mValues = values; } |
212 | | |
213 | | private: |
214 | | /// Sets header type. Only supposed to be used by `KnownHeaders` implementation. |
215 | 0 | void setType(Headers::Type type) noexcept { mType = type; } |
216 | | }; |
217 | | |
218 | | private: |
219 | | /// Internal list of header info entries |
220 | | using TypedHeaders = std::vector<HeaderInfo, StlPoolAllocator<HeaderInfo, PoolBase> >; |
221 | | |
222 | | /// Iterator over used entries in the list |
223 | | template<typename AdoptedIterator> |
224 | | class UsedIterator |
225 | | { |
226 | | friend class KnownHeaders; |
227 | | |
228 | | public: |
229 | | using iterator_category = std::forward_iterator_tag; |
230 | | using difference_type = typename std::iterator_traits<AdoptedIterator>::difference_type; |
231 | | using value_type = typename std::iterator_traits<AdoptedIterator>::value_type; |
232 | | using reference = typename std::iterator_traits<AdoptedIterator>::reference; |
233 | | using pointer = typename std::iterator_traits<AdoptedIterator>::pointer; |
234 | | |
235 | | private: |
236 | | /// Adopted iterator into the list of headers |
237 | | AdoptedIterator mIterator; |
238 | | /// Iterator to the end of the list of headers |
239 | | AdoptedIterator mEnd; |
240 | | |
241 | | public: |
242 | | constexpr UsedIterator() noexcept : mIterator(), mEnd(mIterator) {} |
243 | | UsedIterator(UsedIterator const&) = default; |
244 | | |
245 | | /// Initializing constructor |
246 | | template< |
247 | | typename OtherAdoptedIterator1, |
248 | | typename OtherAdoptedIterator2, |
249 | | typename = typename std::enable_if< |
250 | | std::is_constructible<AdoptedIterator, OtherAdoptedIterator1&&>::value && std::is_constructible<AdoptedIterator, OtherAdoptedIterator2&&>::value |
251 | | >::type |
252 | | > |
253 | | explicit constexpr UsedIterator(OtherAdoptedIterator1&& iter, OtherAdoptedIterator2&& end) |
254 | | noexcept(std::is_nothrow_constructible<AdoptedIterator, OtherAdoptedIterator1&&>::value && |
255 | | std::is_nothrow_constructible<AdoptedIterator, OtherAdoptedIterator2&&>::value) : |
256 | 715k | mIterator(std::forward<OtherAdoptedIterator1>(iter)), |
257 | 715k | mEnd(std::forward<OtherAdoptedIterator2>(end)) |
258 | 715k | { |
259 | 715k | } resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> >::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*>, std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*>, void>(std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*>&&, std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*>&&) Line | Count | Source | 256 | 674k | mIterator(std::forward<OtherAdoptedIterator1>(iter)), | 257 | 674k | mEnd(std::forward<OtherAdoptedIterator2>(end)) | 258 | 674k | { | 259 | 674k | } |
resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> >::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*>&, std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*>, void>(std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*>&, std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*>&&) Line | Count | Source | 256 | 16.5k | mIterator(std::forward<OtherAdoptedIterator1>(iter)), | 257 | 16.5k | mEnd(std::forward<OtherAdoptedIterator2>(end)) | 258 | 16.5k | { | 259 | 16.5k | } |
resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> >::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*>, std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*>, void>(std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*>&&, std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*>&&) Line | Count | Source | 256 | 24.1k | mIterator(std::forward<OtherAdoptedIterator1>(iter)), | 257 | 24.1k | mEnd(std::forward<OtherAdoptedIterator2>(end)) | 258 | 24.1k | { | 259 | 24.1k | } |
|
260 | | |
261 | | /// Convering constructor for mutable -> const iterator conversion |
262 | | template< |
263 | | typename OtherAdoptedIterator, |
264 | | typename = typename std::enable_if< |
265 | | !std::is_same<OtherAdoptedIterator, AdoptedIterator>::value && std::is_constructible<AdoptedIterator, OtherAdoptedIterator const&>::value |
266 | | >::type |
267 | | > |
268 | | constexpr UsedIterator(UsedIterator<OtherAdoptedIterator> const& that) |
269 | | noexcept(std::is_nothrow_constructible<AdoptedIterator, OtherAdoptedIterator const&>::value) : |
270 | 24.1k | mIterator(that.mIterator), |
271 | 24.1k | mEnd(that.mEnd) |
272 | 24.1k | { |
273 | 24.1k | } |
274 | | |
275 | 0 | reference operator*() const noexcept { return *mIterator; }Unexecuted instantiation: resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> >::operator*() const Unexecuted instantiation: resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> >::operator*() const |
276 | 678k | pointer operator->() const noexcept { return mIterator.operator->(); }resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> >::operator->() const Line | Count | Source | 276 | 666k | pointer operator->() const noexcept { return mIterator.operator->(); } |
resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> >::operator->() const Line | Count | Source | 276 | 11.0k | pointer operator->() const noexcept { return mIterator.operator->(); } |
|
277 | 0 | UsedIterator operator++() { increment(); return *this; }Unexecuted instantiation: resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> >::operator++() Unexecuted instantiation: resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> >::operator++() |
278 | 0 | UsedIterator operator++(int) { UsedIterator copy(*this); increment(); return copy; } |
279 | | |
280 | 24.1k | friend bool operator==(UsedIterator const& left, UsedIterator const& right) noexcept { return left.mIterator == right.mIterator; }Unexecuted instantiation: resip::operator==(resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> > const&, resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> > const&) resip::operator==(resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> > const&, resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> > const&) Line | Count | Source | 280 | 24.1k | friend bool operator==(UsedIterator const& left, UsedIterator const& right) noexcept { return left.mIterator == right.mIterator; } |
|
281 | 13.1k | friend bool operator!=(UsedIterator const& left, UsedIterator const& right) noexcept { return !(left == right); }Unexecuted instantiation: resip::operator!=(resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> > const&, resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> > const&) resip::operator!=(resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> > const&, resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> > const&) Line | Count | Source | 281 | 13.1k | friend bool operator!=(UsedIterator const& left, UsedIterator const& right) noexcept { return !(left == right); } |
|
282 | | |
283 | | private: |
284 | | /// Increments the iterator to the next used entry or end of the list |
285 | | void increment() noexcept |
286 | 0 | { |
287 | 0 | ++mIterator; |
288 | 0 | advanceToNextUsedEntry(); |
289 | 0 | } Unexecuted instantiation: resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> >::increment() Unexecuted instantiation: resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> >::increment() |
290 | | |
291 | | /// Advances to the next used entry in the list |
292 | | void advanceToNextUsedEntry() noexcept |
293 | 0 | { |
294 | 0 | while (mIterator != mEnd && mIterator->getType() == Headers::UNKNOWN) |
295 | 0 | ++mIterator; |
296 | 0 | } Unexecuted instantiation: resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo const*> >::advanceToNextUsedEntry() Unexecuted instantiation: resip::SipMessage::KnownHeaders::UsedIterator<std::__1::__wrap_iter<resip::SipMessage::KnownHeaders::HeaderInfo*> >::advanceToNextUsedEntry() |
297 | | }; |
298 | | |
299 | | public: |
300 | | using iterator = UsedIterator<TypedHeaders::iterator>; |
301 | | using const_iterator = UsedIterator<TypedHeaders::const_iterator>; |
302 | | using value_type = TypedHeaders::value_type; |
303 | | using reference = TypedHeaders::reference; |
304 | | using const_reference = TypedHeaders::const_reference; |
305 | | using pointer = TypedHeaders::pointer; |
306 | | using const_pointer = TypedHeaders::const_pointer; |
307 | | using size_type = TypedHeaders::size_type; |
308 | | using difference_type = TypedHeaders::difference_type; |
309 | | using allocator_type = TypedHeaders::allocator_type; |
310 | | |
311 | | private: |
312 | | /// Information about headers |
313 | | TypedHeaders mHeaders; |
314 | | /// Number of non-"unused" elements in the container |
315 | | HeaderIndex mSize; |
316 | | /// Indices into `mHeaders`. If an element is `InvalidHeaderIndex` it means the corresponding header has no entry in the list. |
317 | | HeaderIndex mHeaderIndices[Headers::MAX_HEADERS]; |
318 | | |
319 | | public: |
320 | 0 | KnownHeaders() noexcept : mSize(0) { resetIndices(); } |
321 | | explicit KnownHeaders(const allocator_type& alloc) |
322 | | noexcept(std::is_nothrow_constructible<TypedHeaders, const allocator_type&>::value) : |
323 | 9.32k | mHeaders(alloc), |
324 | 9.32k | mSize(0) |
325 | 9.32k | { |
326 | 9.32k | resetIndices(); |
327 | 9.32k | } |
328 | | |
329 | | // Not copyable or moveable since the container elements may be associated with a memory pool |
330 | | KnownHeaders(const KnownHeaders&) = delete; |
331 | | KnownHeaders& operator=(const KnownHeaders&) = delete; |
332 | | |
333 | | /// Returns `true` if the container is empty. Does not consider "unused" elements. |
334 | 0 | bool empty() const noexcept { return mSize == 0; } |
335 | | /// Returns the number of elements in the container. Does not consider "unused" elements. |
336 | 0 | size_type size() const noexcept { return static_cast<size_type>(mSize); } |
337 | | /// Clears the container. Does not free `HeaderFieldValueList` objects but clears them and marks as "unused". |
338 | | void clear() noexcept; |
339 | | /** |
340 | | * @brief Clears the container and invokes the dispose function on every element. |
341 | | * |
342 | | * The `disposer` function will be called on all entries, including "unused" ones. It is expected to free any resources |
343 | | * associated with the entry and must not throw. |
344 | | */ |
345 | | template<typename Disposer> |
346 | | void clearAndDispose(Disposer&& disposer) noexcept; |
347 | | |
348 | | /// Iterator access |
349 | 0 | const_iterator cbegin() const noexcept { return begin(); } |
350 | 0 | const_iterator cend() const noexcept { return end(); } |
351 | | |
352 | 0 | const_iterator begin() const noexcept { const_iterator it(mHeaders.begin(), mHeaders.end()); it.advanceToNextUsedEntry(); return it; } |
353 | 24.1k | const_iterator end() const noexcept { return const_iterator(mHeaders.end(), mHeaders.end()); } |
354 | | |
355 | 0 | iterator begin() noexcept { iterator it(mHeaders.begin(), mHeaders.end()); it.advanceToNextUsedEntry(); return it; } |
356 | 7.64k | iterator end() noexcept { return iterator(mHeaders.end(), mHeaders.end()); } |
357 | | |
358 | | /// Reserves internal storage for the given number of entries |
359 | 9.32k | void reserve(size_type capacity) { mHeaders.reserve(capacity); } |
360 | | /// Returns capacity of the internal storage |
361 | 0 | size_type capacity() const noexcept { return mHeaders.capacity(); } |
362 | | |
363 | | /// Finds header information, if present in the list. Returns `end()` if not found. Does not produce "unused" entries. |
364 | | iterator find(Headers::Type type) noexcept; |
365 | 24.1k | const_iterator find(Headers::Type type) const noexcept { return const_cast<KnownHeaders*>(this)->find(type); } |
366 | | |
367 | | /// Erases an element. Does not free the `HeaderFieldValueList` object but clears it and marks as "unused". |
368 | | void erase(iterator it) noexcept; |
369 | | |
370 | | /** |
371 | | * @brief Constructs or reuses a previously erased element for a given header type. |
372 | | * |
373 | | * If the header with the given type was previously erased and is in the "unused" state, this call reuses this element. |
374 | | * Otherwise, the call constructs a new element with the given header type and a pointer to the `HeaderFieldValueList` object |
375 | | * returned by the `valuesFactory()` function call. |
376 | | * |
377 | | * @returns An iterator to the inserted element. |
378 | | */ |
379 | | template<typename ValuesFactory> |
380 | | iterator insert(Headers::Type type, ValuesFactory&& valuesFactory); |
381 | | |
382 | | private: |
383 | | /// Resets all header indices to `InvalidHeaderIndex` |
384 | | void resetIndices() noexcept; |
385 | | }; |
386 | | |
387 | | explicit SipMessage(const Tuple *receivedTransport = 0); |
388 | | /// @todo .dlb. public, allows pass by value to compile. |
389 | | SipMessage(const SipMessage& message); |
390 | | |
391 | | /// @todo .dlb. sure would be nice to have overloaded return value here.. |
392 | | virtual Message* clone() const; |
393 | | |
394 | | SipMessage& operator=(const SipMessage& rhs); |
395 | | |
396 | | /// Returns the transaction id from the branch or if 2543, the computed hash. |
397 | | virtual const Data& getTransactionId() const; |
398 | | |
399 | | /** |
400 | | @brief Calculates an MD5 hash over the Request-URI, To tag (for |
401 | | non-INVITE transactions), From tag, Call-ID, CSeq (including |
402 | | the method), and top Via header. The hash is used for |
403 | | transaction matching. |
404 | | */ |
405 | | const Data& getRFC2543TransactionId() const; |
406 | | void setRFC2543TransactionId(const Data& tid); |
407 | | |
408 | | virtual ~SipMessage(); |
409 | | |
410 | | /** @brief Construct a SipMessage object from a string containing a SIP request |
411 | | or response. |
412 | | |
413 | | @param buffer a buffer containing a SIP message |
414 | | @param isExternal true for a message generated externally, false otherwise. |
415 | | @return constructed SipMessage object |
416 | | */ |
417 | | static SipMessage* make(const Data& buffer, bool isExternal = false); |
418 | | void parseAllHeaders(); |
419 | | |
420 | | static bool checkContentLength; |
421 | | |
422 | | /** |
423 | | @brief Base exception for SipMessage related exceptions |
424 | | */ |
425 | | class Exception final : public BaseException |
426 | | { |
427 | | public: |
428 | | /** |
429 | | @brief constructor that records an exception message, the file and the line |
430 | | that the exception occured in. |
431 | | */ |
432 | | Exception(const Data& msg, const Data& file, const int line) |
433 | 0 | : BaseException(msg, file, line) {} |
434 | | /** |
435 | | @brief returns the class name of the exception instance |
436 | | @return the class name of the instance |
437 | | */ |
438 | 0 | const char* name() const noexcept override { return "SipMessage::Exception"; } |
439 | | }; |
440 | | |
441 | | /// Mark message as internally generated |
442 | | inline void setFromTU() |
443 | 0 | { |
444 | 0 | mIsExternal = false; |
445 | 0 | } |
446 | | |
447 | | /// Mark message as externally generated |
448 | | inline void setFromExternal() |
449 | 0 | { |
450 | 0 | mIsExternal = true; |
451 | 0 | } |
452 | | |
453 | | /** |
454 | | @brief Check if SipMessage is to be treated as it came off the wire. |
455 | | |
456 | | @return true if the message came from an IP interface or if it was |
457 | | an internally generated response to an internally generated |
458 | | request (ie: 408), false otherwise. |
459 | | */ |
460 | | inline bool isExternal() const |
461 | 0 | { |
462 | 0 | return mIsExternal; |
463 | 0 | } |
464 | | |
465 | | /** |
466 | | @brief Check if SipMessage came off the wire. |
467 | | |
468 | | @note differs from isExternal(), since isExternal() also returns true |
469 | | for internally generated responses to internally generate requests |
470 | | (ie: 408, etc.). isFromWire only ever returns true if the message |
471 | | actually came off the wire. |
472 | | |
473 | | @return true if the message came from an IP interface, false otherwise. |
474 | | */ |
475 | | inline bool isFromWire() const |
476 | 0 | { |
477 | 0 | return mReceivedTransportTuple.getType() != UNKNOWN_TRANSPORT; |
478 | 0 | } |
479 | | |
480 | | /// @brief Check if SipMessage is a client transaction |
481 | | /// @return true if the message is external and is a response or |
482 | | /// an internally-generated request. |
483 | | virtual bool isClientTransaction() const; |
484 | | |
485 | | /** @brief Generate a string from the SipMessage object |
486 | | |
487 | | @return string representation of a SIP message. |
488 | | */ |
489 | | virtual EncodeStream& encode(EncodeStream& str) const; |
490 | | //sipfrags will not output Content Length if there is no body--introduce |
491 | | //friendship to hide this? |
492 | | virtual EncodeStream& encodeSipFrag(EncodeStream& str) const; |
493 | | EncodeStream& encodeEmbedded(EncodeStream& str) const; |
494 | | |
495 | | virtual EncodeStream& encodeBrief(EncodeStream& str) const; |
496 | | EncodeStream& encodeSingleHeader(Headers::Type type, EncodeStream& str) const; |
497 | | |
498 | | /// Returns true if message is a request, false otherwise |
499 | 0 | inline bool isRequest() const {return mRequest;} |
500 | | /// Returns true if message is a response, false otherwise |
501 | 0 | inline bool isResponse() const {return mResponse;} |
502 | | /// Returns true if message failed to parse, false otherwise |
503 | 0 | inline bool isInvalid() const{return mInvalid;} |
504 | | |
505 | | /// @brief returns the method type of the message |
506 | | /// @see MethodTypes |
507 | | resip::MethodTypes method() const; |
508 | | /// Returns a string containing the SIP method for the message |
509 | | const Data& methodStr() const; |
510 | | |
511 | | /// Returns a string containing the response reason text |
512 | 0 | const resip::Data* getReason() const{return mReason;} |
513 | | |
514 | | /// Returns the RequestLine. This is only valid for request messages. |
515 | | const RequestLine& |
516 | | header(const RequestLineType& l) const; |
517 | | |
518 | | /// Returns the RequestLine. This is only valid for request messages. |
519 | | RequestLine& |
520 | | header(const RequestLineType& l); |
521 | | |
522 | | inline const RequestLine& |
523 | | const_header(const RequestLineType& l) const |
524 | 0 | { |
525 | 0 | return header(l); |
526 | 0 | } |
527 | | |
528 | | /// Returns the StatusLine. This is only valid for response messages. |
529 | | const StatusLine& |
530 | | header(const StatusLineType& l) const; |
531 | | |
532 | | /// Returns the StatusLine. This is only valid for response messages. |
533 | | StatusLine& |
534 | | header(const StatusLineType& l); |
535 | | |
536 | | inline const StatusLine& |
537 | | const_header(const StatusLineType& l) const |
538 | 0 | { |
539 | 0 | return header(l); |
540 | 0 | } |
541 | | |
542 | | /// Returns true if the given header field is present, false otherwise |
543 | | bool exists(const HeaderBase& headerType) const; |
544 | | /// Returns true if the header field is present and non-empty, false otherwise |
545 | | bool empty(const HeaderBase& headerType) const; |
546 | | /// @brief Prevents a header field from being present when the message is prepared |
547 | | /// for sending to a transport. This does not free the memory that was |
548 | | /// used by the header. |
549 | | inline void remove(const HeaderBase& headerType) |
550 | 0 | { |
551 | 0 | remove(headerType.getTypeNum()); |
552 | 0 | } |
553 | | |
554 | | void remove(Headers::Type type); |
555 | | |
556 | | #define defineHeader(_header, _name, _type, _rfc) \ |
557 | | const H_##_header::Type& header(const H_##_header& headerType) const; \ |
558 | | H_##_header::Type& header(const H_##_header& headerType); \ |
559 | | inline const H_##_header::Type& const_header(const H_##_header& headerType) const \ |
560 | 11.0k | {\ |
561 | 11.0k | return header(headerType);\ |
562 | 11.0k | } Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentDisposition const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentEncoding const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_MIMEVersion const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Priority const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Event const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SubscriptionState const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SIPETag const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SIPIfMatch const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentId const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ReferSub const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AnswerMode const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PrivAnswerMode const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentType const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_IdentityInfo const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_From const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_To const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ReplyTo const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ReferTo const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ReferredBy const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PCalledPartyId const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentTransferEncoding const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Organization const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecWebSocketKey const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecWebSocketKey1 const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecWebSocketKey2 const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Origin const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Host const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecWebSocketAccept const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Server const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Subject const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_UserAgent const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Timestamp const&) const resip::SipMessage::const_header(resip::H_ContentLength const&) const Line | Count | Source | 560 | 11.0k | {\ | 561 | 11.0k | return header(headerType);\ | 562 | 11.0k | } |
Unexecuted instantiation: resip::SipMessage::const_header(resip::H_MaxForwards const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_MinExpires const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RSeq const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RetryAfter const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_FlowTimer const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Expires const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SessionExpires const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_MinSE const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_CallID const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Replaces const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_InReplyTo const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Join const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_TargetDialog const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AuthenticationInfo const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_CSeq const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Date const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RAck const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PChargingVector const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PChargingFunctionAddresses const&) const |
563 | | |
564 | | |
565 | | #define defineMultiHeader(_header, _name, _type, _rfc) \ |
566 | | const H_##_header##s::Type& header(const H_##_header##s& headerType) const; \ |
567 | | H_##_header##s::Type& header(const H_##_header##s& headerType); \ |
568 | | inline const H_##_header##s::Type& const_header(const H_##_header##s& headerType) const \ |
569 | 0 | {\ |
570 | 0 | return header(headerType);\ |
571 | 0 | } Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AllowEventss const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Identitys const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AcceptEncodings const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AcceptLanguages const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Allows const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ContentLanguages const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ProxyRequires const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Requires const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Supporteds const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Unsupporteds const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecurityClients const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecurityServers const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_SecurityVerifys const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RequestDispositions const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Reasons const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Privacys const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PMediaAuthorizations const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Accepts const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_CallInfos const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AlertInfos const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ErrorInfos const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RecordRoutes const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Routes const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Contacts const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Paths const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_AcceptContacts const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RejectContacts const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PAssertedIdentitys const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PPreferredIdentitys const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PAssociatedUris const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ServiceRoutes const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_RemotePartyIds const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_HistoryInfos const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Cookies const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Authorizations const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ProxyAuthenticates const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_ProxyAuthorizations const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_WWWAuthenticates const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Warnings const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_Vias const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PAccessNetworkInfos const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_PVisitedNetworkIDs const&) const Unexecuted instantiation: resip::SipMessage::const_header(resip::H_UserToUsers const&) const |
572 | | |
573 | | defineHeader(ContentDisposition, "Content-Disposition", Token, "RFC 3261"); |
574 | | defineHeader(ContentEncoding, "Content-Encoding", Token, "RFC 3261"); |
575 | | defineHeader(MIMEVersion, "Mime-Version", Token, "RFC 3261"); |
576 | | defineHeader(Priority, "Priority", Token, "RFC 3261"); |
577 | | defineHeader(Event, "Event", Token, "RFC 3265"); |
578 | | defineHeader(SubscriptionState, "Subscription-State", Token, "RFC 3265"); |
579 | | defineHeader(SIPETag, "SIP-ETag", Token, "RFC 3903"); |
580 | | defineHeader(SIPIfMatch, "SIP-If-Match", Token, "RFC 3903"); |
581 | | defineHeader(ContentId, "Content-ID", Token, "RFC 2045"); |
582 | | defineMultiHeader(AllowEvents, "Allow-Events", Token, "RFC 3265"); |
583 | | defineMultiHeader(Identity, "Identity", StringCategory, "RFC 8224"); // Originally defined in RFC 4474 as a single header, but later modified by RFC8224 to be a multiheader |
584 | | defineMultiHeader(AcceptEncoding, "Accept-Encoding", Token, "RFC 3261"); |
585 | | defineMultiHeader(AcceptLanguage, "Accept-Language", Token, "RFC 3261"); |
586 | | defineMultiHeader(Allow, "Allow", Token, "RFC 3261"); |
587 | | defineMultiHeader(ContentLanguage, "Content-Language", Token, "RFC 3261"); |
588 | | defineMultiHeader(ProxyRequire, "Proxy-Require", Token, "RFC 3261"); |
589 | | defineMultiHeader(Require, "Require", Token, "RFC 3261"); |
590 | | defineMultiHeader(Supported, "Supported", Token, "RFC 3261"); |
591 | | defineMultiHeader(Unsupported, "Unsupported", Token, "RFC 3261"); |
592 | | defineMultiHeader(SecurityClient, "Security-Client", Token, "RFC 3329"); |
593 | | defineMultiHeader(SecurityServer, "Security-Server", Token, "RFC 3329"); |
594 | | defineMultiHeader(SecurityVerify, "Security-Verify", Token, "RFC 3329"); |
595 | | defineMultiHeader(RequestDisposition, "Request-Disposition", Token, "RFC 3841"); |
596 | | defineMultiHeader(Reason, "Reason", Token, "RFC 3326"); |
597 | | defineMultiHeader(Privacy, "Privacy", PrivacyCategory, "RFC 3323"); |
598 | | defineMultiHeader(PMediaAuthorization, "P-Media-Authorization", Token, "RFC 3313"); |
599 | | defineHeader(ReferSub, "Refer-Sub", Token, "RFC 4488"); |
600 | | defineHeader(AnswerMode, "Answer-Mode", Token, "draft-ietf-answermode-04"); |
601 | | defineHeader(PrivAnswerMode, "Priv-Answer-Mode", Token, "draft-ietf-answermode-04"); |
602 | | |
603 | | defineMultiHeader(Accept, "Accept", Mime, "RFC 3261"); |
604 | | defineHeader(ContentType, "Content-Type", Mime, "RFC 3261"); |
605 | | |
606 | | defineMultiHeader(CallInfo, "Call-Info", GenericUri, "RFC 3261"); |
607 | | defineMultiHeader(AlertInfo, "Alert-Info", GenericUri, "RFC 3261"); |
608 | | defineMultiHeader(ErrorInfo, "Error-Info", GenericUri, "RFC 3261"); |
609 | | defineHeader(IdentityInfo, "Identity-Info", GenericUri, "RFC 4474"); |
610 | | |
611 | | defineMultiHeader(RecordRoute, "Record-Route", NameAddr, "RFC 3261"); |
612 | | defineMultiHeader(Route, "Route", NameAddr, "RFC 3261"); |
613 | | defineMultiHeader(Contact, "Contact", NameAddr, "RFC 3261"); |
614 | | defineHeader(From, "From", NameAddr, "RFC 3261"); |
615 | | defineHeader(To, "To", NameAddr, "RFC 3261"); |
616 | | defineHeader(ReplyTo, "Reply-To", NameAddr, "RFC 3261"); |
617 | | defineHeader(ReferTo, "Refer-To", NameAddr, "RFC 3515"); |
618 | | defineHeader(ReferredBy, "Referred-By", NameAddr, "RFC 3892"); |
619 | | defineMultiHeader(Path, "Path", NameAddr, "RFC 3327"); |
620 | | defineMultiHeader(AcceptContact, "Accept-Contact", NameAddr, "RFC 3841"); |
621 | | defineMultiHeader(RejectContact, "Reject-Contact", NameAddr, "RFC 3841"); |
622 | | defineMultiHeader(PAssertedIdentity, "P-Asserted-Identity", NameAddr, "RFC 3325"); |
623 | | defineMultiHeader(PPreferredIdentity, "P-Preferred-Identity", NameAddr, "RFC 3325"); |
624 | | defineHeader(PCalledPartyId, "P-Called-Party-ID", NameAddr, "RFC 3455"); |
625 | | defineMultiHeader(PAssociatedUri, "P-Associated-URI", NameAddr, "RFC 3455"); |
626 | | defineMultiHeader(ServiceRoute, "Service-Route", NameAddr, "RFC 3608"); |
627 | | defineMultiHeader(RemotePartyId, "Remote-Party-ID", NameAddr, "draft-ietf-sip-privacy-04"); // ?bwc? Not in 3323, should we keep? |
628 | | defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244"); |
629 | | |
630 | | defineHeader(ContentTransferEncoding, "Content-Transfer-Encoding", StringCategory, "RFC 1521"); |
631 | | defineHeader(Organization, "Organization", StringCategory, "RFC 3261"); |
632 | | defineHeader(SecWebSocketKey, "Sec-WebSocket-Key", StringCategory, "RFC 6455"); |
633 | | defineHeader(SecWebSocketKey1, "Sec-WebSocket-Key1", StringCategory, "draft-hixie- thewebsocketprotocol-76"); |
634 | | defineHeader(SecWebSocketKey2, "Sec-WebSocket-Key2", StringCategory, "draft-hixie- thewebsocketprotocol-76"); |
635 | | defineHeader(Origin, "Origin", StringCategory, "draft-hixie- thewebsocketprotocol-76"); |
636 | | defineHeader(Host, "Host", StringCategory, "draft-hixie- thewebsocketprotocol-76"); |
637 | | defineHeader(SecWebSocketAccept, "Sec-WebSocket-Accept", StringCategory, "RFC 6455"); |
638 | | defineMultiHeader(Cookie, "Cookie", StringCategory, "RFC 6265"); |
639 | | defineHeader(Server, "Server", StringCategory, "RFC 3261"); |
640 | | defineHeader(Subject, "Subject", StringCategory, "RFC 3261"); |
641 | | defineHeader(UserAgent, "User-Agent", StringCategory, "RFC 3261"); |
642 | | defineHeader(Timestamp, "Timestamp", StringCategory, "RFC 3261"); |
643 | | |
644 | | defineHeader(ContentLength, "Content-Length", UInt32Category, "RFC 3261"); |
645 | | defineHeader(MaxForwards, "Max-Forwards", UInt32Category, "RFC 3261"); |
646 | | defineHeader(MinExpires, "Min-Expires", UInt32Category, "RFC 3261"); |
647 | | defineHeader(RSeq, "RSeq", UInt32Category, "RFC 3261"); |
648 | | |
649 | | /// @todo !dlb! this one is not quite right -- can have (comment) after field value |
650 | | defineHeader(RetryAfter, "Retry-After", UInt32Category, "RFC 3261"); |
651 | | defineHeader(FlowTimer, "Flow-Timer", UInt32Category, "RFC 5626"); |
652 | | |
653 | | defineHeader(Expires, "Expires", ExpiresCategory, "RFC 3261"); |
654 | | defineHeader(SessionExpires, "Session-Expires", ExpiresCategory, "RFC 4028"); |
655 | | defineHeader(MinSE, "Min-SE", ExpiresCategory, "RFC 4028"); |
656 | | |
657 | | defineHeader(CallID, "Call-ID", CallID, "RFC 3261"); |
658 | | defineHeader(Replaces, "Replaces", CallID, "RFC 3891"); |
659 | | defineHeader(InReplyTo, "In-Reply-To", CallID, "RFC 3261"); |
660 | | defineHeader(Join, "Join", CallId, "RFC 3911"); |
661 | | defineHeader(TargetDialog, "Target-Dialog", CallId, "RFC 4538"); |
662 | | |
663 | | defineHeader(AuthenticationInfo, "Authentication-Info", Auth, "RFC 3261"); |
664 | | defineMultiHeader(Authorization, "Authorization", Auth, "RFC 3261"); |
665 | | defineMultiHeader(ProxyAuthenticate, "Proxy-Authenticate", Auth, "RFC 3261"); |
666 | | defineMultiHeader(ProxyAuthorization, "Proxy-Authorization", Auth, "RFC 3261"); |
667 | | defineMultiHeader(WWWAuthenticate, "Www-Authenticate", Auth, "RFC 3261"); |
668 | | |
669 | | defineHeader(CSeq, "CSeq", CSeqCategory, "RFC 3261"); |
670 | | defineHeader(Date, "Date", DateCategory, "RFC 3261"); |
671 | | defineMultiHeader(Warning, "Warning", WarningCategory, "RFC 3261"); |
672 | | defineMultiHeader(Via, "Via", Via, "RFC 3261"); |
673 | | defineHeader(RAck, "RAck", RAckCategory, "RFC 3262"); |
674 | | |
675 | | defineMultiHeader(PAccessNetworkInfo, "P-Access-Network-Info", Token, "RFC 7315"); // section 5.4. |
676 | | defineHeader(PChargingVector, "P-Charging-Vector", Token, "RFC 3455"); |
677 | | defineHeader(PChargingFunctionAddresses, "P-Charging-Function-Addresses", Token, "RFC 3455"); |
678 | | defineMultiHeader(PVisitedNetworkID, "P-Visited-Network-ID", TokenOrQuotedStringCategory, "RFC 3455"); |
679 | | |
680 | | defineMultiHeader(UserToUser, "User-to-User", TokenOrQuotedStringCategory, "draft-ietf-cuss-sip-uui-17"); |
681 | | |
682 | | /// unknown header interface |
683 | | const StringCategories& header(const ExtensionHeader& symbol) const; |
684 | | StringCategories& header(const ExtensionHeader& symbol); |
685 | | bool exists(const ExtensionHeader& symbol) const; |
686 | | void remove(const ExtensionHeader& symbol); |
687 | | |
688 | | /// typeless header interface |
689 | | const HeaderFieldValueList* getRawHeader(Headers::Type headerType) const; |
690 | | void setRawHeader(const HeaderFieldValueList* hfvs, Headers::Type headerType); |
691 | 0 | const KnownHeaders& getRawHeaders() const noexcept { return mKnownHeaders; } |
692 | 0 | const UnknownHeaders& getRawUnknownHeaders() const noexcept { return mUnknownHeaders; } |
693 | | /** |
694 | | Return the raw body string (if it exists). The returned HFV |
695 | | and its underlying memory is owned by the SipMessage, and may |
696 | | be released when this SipMessage is manipulated. |
697 | | |
698 | | This is a low-level interface; see getContents() for higher level. |
699 | | **/ |
700 | 0 | const HeaderFieldValue& getRawBody() const noexcept { return mContentsHfv; } |
701 | | |
702 | | /** |
703 | | Remove any existing body/contents, and (if non-empty) |
704 | | set the body to {body}. It makes full copy of the body |
705 | | to stored within the SipMessage (since lifetime of |
706 | | the message is unpredictable). |
707 | | |
708 | | This is a low-level interface; see setContents() for higher level. |
709 | | **/ |
710 | | void setRawBody(const HeaderFieldValue& body); |
711 | | |
712 | | /** @brief Retrieves the body of a SIP message. |
713 | | * |
714 | | * In the case of an INVITE request containing SDP, the body would |
715 | | * be an SdpContents. For a MESSAGE request, the body may be PlainContents, |
716 | | * CpimContents, or another subclass of Contents. |
717 | | * |
718 | | * @return pointer to the contents of the SIP message |
719 | | **/ |
720 | | Contents* getContents() const; |
721 | | /// Removes the contents from the message |
722 | | std::unique_ptr<Contents> releaseContents(); |
723 | | |
724 | | /// @brief Set the contents of the message |
725 | | /// @param contents to store in the message |
726 | | void setContents(const Contents* contents); |
727 | | /// @brief Set the contents of the message |
728 | | /// @param contents to store in the message |
729 | | void setContents(std::unique_ptr<Contents> contents); |
730 | | |
731 | | /// @internal transport interface |
732 | | void setStartLine(const char* start, int len); |
733 | | |
734 | | void setBody(const char* start, uint32_t len); |
735 | | |
736 | | /// Add HeaderFieldValue given enum, header name, pointer start, content length |
737 | | void addHeader(Headers::Type header, |
738 | | const char* headerName, int headerLen, |
739 | | const char* start, int len); |
740 | | |
741 | | // Returns the source tuple for the transport that the message was received from |
742 | | // only makes sense for messages received from the wire. Differs from Source |
743 | | // since it contains the transport bind address instead of the actual source |
744 | | // address. |
745 | 0 | const Tuple& getReceivedTransportTuple() const { return mReceivedTransportTuple; } |
746 | | |
747 | | /// Set Tuple for transport from whence this message came |
748 | 0 | void setReceivedTransportTuple(const Tuple& transportTuple) { mReceivedTransportTuple = transportTuple;} |
749 | | |
750 | | // Returns the source tuple that the message was received from |
751 | | // only makes sense for messages received from the wire |
752 | 0 | void setSource(const Tuple& tuple) { mSource = tuple; } |
753 | | /// @brief Returns the source tuple that the message was received from |
754 | | /// only makes sense for messages received from the wire |
755 | 0 | const Tuple& getSource() const { return mSource; } |
756 | | |
757 | | /// Used by the stateless interface to specify where to send a request/response |
758 | 0 | void setDestination(const Tuple& tuple) { mDestination = tuple; } |
759 | 0 | Tuple& getDestination() { return mDestination; } |
760 | | |
761 | | void addBuffer(char* buf); |
762 | | |
763 | 0 | uint64_t getCreatedTimeMicroSec() const {return mCreatedTime;} |
764 | | |
765 | | /// deal with a notion of an "out-of-band" forced target for SIP routing |
766 | | void setForceTarget(const Uri& uri); |
767 | | void clearForceTarget(); |
768 | | const Uri& getForceTarget() const; |
769 | | bool hasForceTarget() const; |
770 | | |
771 | 0 | const Data& getTlsDomain() const { return mTlsDomain; } |
772 | 0 | void setTlsDomain(const Data& domain) { mTlsDomain = domain; } |
773 | | |
774 | 0 | const std::list<Data>& getTlsPeerNames() const { return mTlsPeerNames; } |
775 | 0 | void setTlsPeerNames(const std::list<Data>& tlsPeerNames) { mTlsPeerNames = tlsPeerNames; } |
776 | | |
777 | 0 | const CookieList& getWsCookies() const { return mWsCookies; } |
778 | 0 | void setWsCookies(const CookieList& wsCookies) { mWsCookies = wsCookies; } |
779 | | |
780 | 0 | std::shared_ptr<WsCookieContext> getWsCookieContext() const noexcept { return mWsCookieContext; } |
781 | 0 | void setWsCookieContext(std::shared_ptr<WsCookieContext> wsCookieContext) noexcept { mWsCookieContext = wsCookieContext; } |
782 | | |
783 | | Data getCanonicalIdentityString() const; |
784 | | |
785 | | SipMessage& mergeUri(const Uri& source); |
786 | | |
787 | | void setSecurityAttributes(std::unique_ptr<SecurityAttributes>) noexcept; |
788 | 0 | const SecurityAttributes* getSecurityAttributes() const noexcept { return mSecurityAttributes.get(); } |
789 | | |
790 | | /// @brief Call a MessageDecorator to process the message before it is |
791 | | /// sent to the transport |
792 | 0 | void addOutboundDecorator(std::unique_ptr<MessageDecorator> md){mOutboundDecorators.push_back(md.release());} |
793 | | void clearOutboundDecorators(); |
794 | | void callOutboundDecorators(const Tuple &src, |
795 | | const Tuple &dest, |
796 | | const Data& sigcompId); |
797 | | void rollbackOutboundDecorators(); |
798 | | void copyOutboundDecoratorsToStackCancel(SipMessage& cancel); |
799 | | void copyOutboundDecoratorsToStackFailureAck(SipMessage& ack); |
800 | | bool mIsDecorated; |
801 | | |
802 | | bool mIsBadAck200; |
803 | | |
804 | | protected: |
805 | | // !bwc! Removes or zeros all pointers to heap-allocated memory this |
806 | | // class owns. |
807 | | void clear(bool leaveResponseStuff=false); |
808 | | // !bwc! Frees all heap-allocated memory owned. |
809 | | void freeMem(bool leaveResponseStuff=false); |
810 | | // Clears mHeaders and cleans up memory |
811 | | void clearHeaders(); |
812 | | |
813 | | // !bwc! Initializes members. Will not free heap-allocated memory. |
814 | | // Will begin by calling clear(). |
815 | | void init(const SipMessage& rhs); |
816 | | |
817 | | private: |
818 | | void compute2543TransactionHash() const; |
819 | | |
820 | | EncodeStream& |
821 | | encode(EncodeStream& str, bool isSipFrag) const; |
822 | | |
823 | | void copyFrom(const SipMessage& message); |
824 | | |
825 | | HeaderFieldValueList* ensureHeaders(Headers::Type type); |
826 | | HeaderFieldValueList* ensureHeaders(Headers::Type type) const; // throws if not present |
827 | | |
828 | | HeaderFieldValueList* ensureHeader(Headers::Type type); |
829 | | HeaderFieldValueList* ensureHeader(Headers::Type type) const; // throws if not present |
830 | | |
831 | | void throwHeaderMissing(Headers::Type type) const; |
832 | | |
833 | | inline HeaderFieldValueList* getEmptyHfvl() |
834 | 12.6k | { |
835 | 12.6k | void* ptr(mPool.allocate(sizeof(HeaderFieldValueList))); |
836 | 12.6k | return new (ptr) HeaderFieldValueList(mPool); |
837 | 12.6k | } |
838 | | |
839 | | inline HeaderFieldValueList* getCopyHfvl(const HeaderFieldValueList& hfvl) |
840 | 0 | { |
841 | 0 | void* ptr(mPool.allocate(sizeof(HeaderFieldValueList))); |
842 | 0 | return new (ptr) HeaderFieldValueList(hfvl, mPool); |
843 | 0 | } |
844 | | |
845 | | inline void freeHfvl(HeaderFieldValueList* hfvl) |
846 | 12.6k | { |
847 | 12.6k | if(hfvl) |
848 | 12.6k | { |
849 | 12.6k | hfvl->~HeaderFieldValueList(); |
850 | 12.6k | mPool.deallocate(hfvl); |
851 | 12.6k | } |
852 | 12.6k | } |
853 | | |
854 | | template<class T> |
855 | | ParserContainer<T>* makeParserContainer() |
856 | | { |
857 | | void* ptr(mPool.allocate(sizeof(ParserContainer<T>))); |
858 | | return new (ptr) ParserContainer<T>(mPool); |
859 | | } |
860 | | |
861 | | template<class T> |
862 | | ParserContainer<T>* makeParserContainer(HeaderFieldValueList* hfvs, |
863 | | Headers::Type type = Headers::UNKNOWN) |
864 | 276 | { |
865 | 276 | void* ptr(mPool.allocate(sizeof(ParserContainer<T>))); |
866 | 276 | return new (ptr) ParserContainer<T>(hfvs, type, mPool); |
867 | 276 | } Unexecuted instantiation: resip::ParserContainer<resip::StringCategory>* resip::SipMessage::makeParserContainer<resip::StringCategory>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::Token>* resip::SipMessage::makeParserContainer<resip::Token>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::PrivacyCategory>* resip::SipMessage::makeParserContainer<resip::PrivacyCategory>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::Mime>* resip::SipMessage::makeParserContainer<resip::Mime>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::GenericUri>* resip::SipMessage::makeParserContainer<resip::GenericUri>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::NameAddr>* resip::SipMessage::makeParserContainer<resip::NameAddr>(resip::HeaderFieldValueList*, resip::Headers::Type) resip::ParserContainer<resip::UInt32Category>* resip::SipMessage::makeParserContainer<resip::UInt32Category>(resip::HeaderFieldValueList*, resip::Headers::Type) Line | Count | Source | 864 | 276 | { | 865 | 276 | void* ptr(mPool.allocate(sizeof(ParserContainer<T>))); | 866 | 276 | return new (ptr) ParserContainer<T>(hfvs, type, mPool); | 867 | 276 | } |
Unexecuted instantiation: resip::ParserContainer<resip::ExpiresCategory>* resip::SipMessage::makeParserContainer<resip::ExpiresCategory>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::CallID>* resip::SipMessage::makeParserContainer<resip::CallID>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::Auth>* resip::SipMessage::makeParserContainer<resip::Auth>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::CSeqCategory>* resip::SipMessage::makeParserContainer<resip::CSeqCategory>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::DateCategory>* resip::SipMessage::makeParserContainer<resip::DateCategory>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::WarningCategory>* resip::SipMessage::makeParserContainer<resip::WarningCategory>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::Via>* resip::SipMessage::makeParserContainer<resip::Via>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::RAckCategory>* resip::SipMessage::makeParserContainer<resip::RAckCategory>(resip::HeaderFieldValueList*, resip::Headers::Type) Unexecuted instantiation: resip::ParserContainer<resip::TokenOrQuotedStringCategory>* resip::SipMessage::makeParserContainer<resip::TokenOrQuotedStringCategory>(resip::HeaderFieldValueList*, resip::Headers::Type) |
868 | | |
869 | | // indicates this message came from the wire or we want it to look like it |
870 | | // came from the wire (ie. internally generated responses to an internally |
871 | | // generated request), set by the Transport and setFromTu and setFromExternal APIs |
872 | | bool mIsExternal; |
873 | | |
874 | | // Sizing so that average SipMessages don't need to allocate heap memory |
875 | | // To profile current sizing, enable DINKYPOOL_PROFILING in SipMessage.cxx |
876 | | // and look for DebugLog message in SipMessage destructor to know when heap |
877 | | // allocations are occuring and how much of the pool is used. |
878 | | DinkyPool<3732> mPool; |
879 | | |
880 | | // raw text corresponding to each typed header (not yet parsed) |
881 | | KnownHeaders mKnownHeaders; |
882 | | |
883 | | // raw text corresponding to each unknown header |
884 | | UnknownHeaders mUnknownHeaders; |
885 | | |
886 | | // For messages received from the wire, this indicates information about |
887 | | // the transport the message was received on |
888 | | Tuple mReceivedTransportTuple; |
889 | | |
890 | | // For messages received from the wire, this indicates where it came |
891 | | // from. Can be used to get to the Transport and/or reliable Connection |
892 | | Tuple mSource; |
893 | | |
894 | | // Used by the TU to specify where a message is to go |
895 | | Tuple mDestination; |
896 | | |
897 | | // Raw buffers coming from the Transport. message manages the memory |
898 | | std::vector<char*> mBufferList; |
899 | | |
900 | | // special case for the first line of message |
901 | | StartLine* mStartLine; |
902 | | char mStartLineMem[sizeof(RequestLine) > sizeof(StatusLine) ? sizeof(RequestLine) : sizeof(StatusLine)]; |
903 | | |
904 | | // raw text for the contents (all of them) |
905 | | HeaderFieldValue mContentsHfv; |
906 | | |
907 | | // lazy parser for the contents |
908 | | mutable Contents* mContents; |
909 | | |
910 | | // cached value of a hash of the transaction id for a message received |
911 | | // from a 2543 sip element. as per rfc3261 see 17.2.3 |
912 | | mutable Data mRFC2543TransactionId; |
913 | | |
914 | | // is a request or response |
915 | | bool mRequest; |
916 | | bool mResponse; |
917 | | |
918 | | bool mInvalid; |
919 | | resip::Data* mReason; |
920 | | |
921 | | uint64_t mCreatedTime; |
922 | | |
923 | | // used when next element is a strict router OR |
924 | | // client forces next hop OOB |
925 | | Uri* mForceTarget; |
926 | | |
927 | | // domain associated with this message for tls cert |
928 | | Data mTlsDomain; |
929 | | |
930 | | // peers domain associate with this message (MTLS) |
931 | | std::list<Data> mTlsPeerNames; |
932 | | |
933 | | // cookies associated with this message from the WebSocket Upgrade request |
934 | | CookieList mWsCookies; |
935 | | |
936 | | // parsed cookie authentication elements associated with this message from the WebSocket Upgrade request |
937 | | std::shared_ptr<WsCookieContext> mWsCookieContext; |
938 | | |
939 | | std::unique_ptr<SecurityAttributes> mSecurityAttributes; |
940 | | |
941 | | std::vector<MessageDecorator*> mOutboundDecorators; |
942 | | |
943 | | friend class TransportSelector; |
944 | | }; |
945 | | |
946 | | } |
947 | | |
948 | | #undef ensureHeaderTypeUseable |
949 | | #undef ensureSingleHeader |
950 | | #undef ensureMultiHeader |
951 | | #undef defineHeader |
952 | | #undef defineMultiHeader |
953 | | |
954 | | #endif |
955 | | |
956 | | /* ==================================================================== |
957 | | * The Vovida Software License, Version 1.0 |
958 | | * |
959 | | * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. |
960 | | * |
961 | | * Redistribution and use in source and binary forms, with or without |
962 | | * modification, are permitted provided that the following conditions |
963 | | * are met: |
964 | | * |
965 | | * 1. Redistributions of source code must retain the above copyright |
966 | | * notice, this list of conditions and the following disclaimer. |
967 | | * |
968 | | * 2. Redistributions in binary form must reproduce the above copyright |
969 | | * notice, this list of conditions and the following disclaimer in |
970 | | * the documentation and/or other materials provided with the |
971 | | * distribution. |
972 | | * |
973 | | * 3. The names "VOCAL", "Vovida Open Communication Application Library", |
974 | | * and "Vovida Open Communication Application Library (VOCAL)" must |
975 | | * not be used to endorse or promote products derived from this |
976 | | * software without prior written permission. For written |
977 | | * permission, please contact vocal@vovida.org. |
978 | | * |
979 | | * 4. Products derived from this software may not be called "VOCAL", nor |
980 | | * may "VOCAL" appear in their name, without prior written |
981 | | * permission of Vovida Networks, Inc. |
982 | | * |
983 | | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
984 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
985 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND |
986 | | * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA |
987 | | * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES |
988 | | * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, |
989 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
990 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
991 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
992 | | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
993 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
994 | | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
995 | | * DAMAGE. |
996 | | * |
997 | | * ==================================================================== |
998 | | * |
999 | | * This software consists of voluntary contributions made by Vovida |
1000 | | * Networks, Inc. and many individuals on behalf of Vovida Networks, |
1001 | | * Inc. For more information on Vovida Networks, Inc., please see |
1002 | | * <http://www.vovida.org/>. |
1003 | | * |
1004 | | * vi: set shiftwidth=3 expandtab: |
1005 | | */ |