reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
SipMessage.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
11#include "rutil/Coders.hxx"
12#include "rutil/CountStream.hxx"
13#include "rutil/Logger.hxx"
15#include "rutil/compat.hxx"
16#include "rutil/vmd5.hxx"
17#include "rutil/Random.hxx"
18#include "rutil/ParseBuffer.hxx"
20//#include "rutil/WinLeakCheck.hxx" // not compatible with placement new used below
21#include <utility>
22
23using namespace resip;
24using namespace std;
25
26#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
27
29void
31{
32 if (mSize > 0)
33 {
34 for (reference elem : mHeaders)
35 {
36 if (elem.getType() != Headers::UNKNOWN)
37 {
38 elem.getValues()->clear();
39 elem.setType(Headers::UNKNOWN);
40 }
41 }
42
43 for (UsedBitMaskWord& word : mUsedBitMask)
44 {
45 word = 0u;
46 }
47
48 mSize = 0u;
49 }
50}
51
53template<typename Disposer>
54inline void
55SipMessage::KnownHeaders::clearAndDispose(Disposer&& disposer) noexcept
56{
57 for (reference elem : mHeaders)
58 {
59 disposer(elem);
60 }
61
62 mHeaders.clear();
63 mSize = 0u;
64 resetIndices();
65}
66
68void
70{
71 const Headers::Type type = it->getType();
73 resip_assert(it->getValues() != nullptr);
74 resip_assert(mSize > 0);
75
76 it->getValues()->clear();
77 it->setType(Headers::UNKNOWN);
78
79 mUsedBitMask[static_cast<unsigned int>(type) / UsedBitMaskWordBits] &=
80 ~(static_cast<UsedBitMaskWord>(1u) << (static_cast<unsigned int>(type) % UsedBitMaskWordBits));
81
82 --mSize;
83}
84
86template<typename ValuesFactory>
88SipMessage::KnownHeaders::insert(Headers::Type type, ValuesFactory&& valuesFactory)
89{
90 resip_assert(static_cast<size_type>(type) < (sizeof(mHeaderIndices) / sizeof(*mHeaderIndices)));
91 size_type pos = mHeaderIndices[type];
92 if (pos >= mHeaders.size())
93 {
94 pos = mHeaders.size();
95 mHeaders.emplace_back(type);
96 try
97 {
98 mHeaders[pos].setValues(valuesFactory());
99 }
100 catch (...)
101 {
102 mHeaders.pop_back();
103 throw;
104 }
105 mHeaderIndices[type] = static_cast<HeaderIndex>(pos);
106 ++mSize;
107 }
108 else if (mHeaders[pos].getType() == Headers::UNKNOWN)
109 {
110 // Reuse the previously erased element
111 mHeaders[pos].setType(type);
112 ++mSize;
113 }
114
115 mUsedBitMask[static_cast<unsigned int>(type) / UsedBitMaskWordBits] |=
116 static_cast<UsedBitMaskWord>(1u) << (static_cast<unsigned int>(type) % UsedBitMaskWordBits);
117
118 return iterator(mHeaders.begin() + pos, mHeaders.end());
119}
120
122void
123SipMessage::KnownHeaders::resetIndices() noexcept
124{
125 for (HeaderIndex& index : mHeaderIndices)
126 {
127 index = InvalidHeaderIndex;
128 }
129
130 for (UsedBitMaskWord& word : mUsedBitMask)
131 {
132 word = 0u;
133 }
134}
135
139{
140 resip_assert(static_cast<size_type>(type) < (sizeof(mHeaderIndices) / sizeof(*mHeaderIndices)));
141 if (mHeaderIndices[type] < mHeaders.size())
142 {
143 TypedHeaders::iterator it = mHeaders.begin() + mHeaderIndices[type];
144 if (it->getType() != Headers::UNKNOWN)
145 return iterator(it, mHeaders.end());
146 }
147
148 return end();
149}
150
151
153
154SipMessage::SipMessage(const Tuple *receivedTransportTuple)
155 : mIsDecorated(false),
156 mIsBadAck200(false),
157 mIsExternal(receivedTransportTuple != 0), // may be modified later by setFromTU or setFromExternal
158 mKnownHeaders(StlPoolAllocator<HeaderFieldValueList*, PoolBase>(&mPool)),
159#ifndef __SUNPRO_CC
160 mUnknownHeaders(StlPoolAllocator<std::pair<Data, HeaderFieldValueList*>, PoolBase>(&mPool)),
161#else
162 mUnknownHeaders(),
163#endif
164 mRequest(false),
165 mResponse(false),
166 mInvalid(false),
167 mCreatedTime(Timer::getTimeMicroSec()),
168 mTlsDomain(Data::Empty)
169{
170 if(receivedTransportTuple)
171 {
172 mReceivedTransportTuple = *receivedTransportTuple;
173 }
174 // !bwc! TODO make this tunable
175 mKnownHeaders.reserve(16);
176 clear();
177}
178
180 : mKnownHeaders(StlPoolAllocator<HeaderFieldValueList*, PoolBase>(&mPool)),
181#ifndef __SUNPRO_CC
182 mUnknownHeaders(StlPoolAllocator<std::pair<Data, HeaderFieldValueList*>, PoolBase>(&mPool)),
183#else
184 mUnknownHeaders(),
185#endif
186 mCreatedTime(Timer::getTimeMicroSec())
187{
188 init(from);
189}
190
191Message*
193{
194 return new SipMessage(*this);
195}
196
199{
200 if (this != &rhs)
201 {
202 freeMem();
203 init(rhs);
204 }
205 return *this;
206}
207
209{
210//#define DINKYPOOL_PROFILING
211#ifdef DINKYPOOL_PROFILING
212 if (mPool.getHeapBytes() > 0)
213 {
214 InfoLog(<< "SipMessage mPool filled up and used " << mPool.getHeapBytes() << " bytes on the heap, consider increasing the mPool size (sizeof SipMessage is " << sizeof(SipMessage) << " bytes): msg="
215 << std::endl << *this);
216 }
217 else
218 {
219 InfoLog(<< "SipMessage mPool used " << mPool.getPoolBytes() << " bytes of a total " << mPool.getPoolSizeBytes() << " bytes (sizeof SipMessage is " << sizeof(SipMessage) << " bytes): msg="
220 << std::endl << *this);
221 }
222#endif
223 freeMem();
224}
225
226void
227SipMessage::clear(bool leaveResponseStuff)
228{
229 if(!leaveResponseStuff)
230 {
231 clearHeaders();
232
233 mBufferList.clear();
234 }
235
236 mUnknownHeaders.clear();
237
238 mStartLine = nullptr;
239 mContents = nullptr;
240 mContentsHfv.clear();
241 mForceTarget = nullptr;
242 mReason = nullptr;
243 mOutboundDecorators.clear();
244}
245
246void
248{
249 clear();
250
253 mIsExternal = rhs.mIsExternal;
254 mReceivedTransportTuple = rhs.mReceivedTransportTuple;
255 mSource = rhs.mSource;
256 mDestination = rhs.mDestination;
257 mRFC2543TransactionId = rhs.mRFC2543TransactionId;
258 mRequest = rhs.mRequest;
259 mResponse = rhs.mResponse;
260 mInvalid = rhs.mInvalid;
261 if(!rhs.mReason)
262 {
263 mReason = nullptr;
264 }
265 else
266 {
267 mReason = new Data(*rhs.mReason);
268 }
269 mTlsDomain = rhs.mTlsDomain;
270 mConnectionInfo = rhs.mConnectionInfo;
271
272 mKnownHeaders.reserve(rhs.mKnownHeaders.size());
273 for (KnownHeaders::const_reference info : rhs.mKnownHeaders)
274 {
275 // At this point the list must have no "unused" elements,
276 // so the factory function will always be invoked
277 mKnownHeaders.insert(info.getType(), [&] { return getCopyHfvl(*info.getValues()); });
278 }
279
280 for (UnknownHeaders::const_iterator i = rhs.mUnknownHeaders.begin();
281 i != rhs.mUnknownHeaders.end(); ++i)
282 {
283 mUnknownHeaders.push_back(pair<Data, HeaderFieldValueList*>(
284 i->first,
285 getCopyHfvl(*i->second)));
286 }
287 if (rhs.mStartLine != nullptr)
288 {
289 mStartLine = rhs.mStartLine->clone(mStartLineMem);
290 }
291 if (rhs.mContents != nullptr)
292 {
293 mContents = rhs.mContents->clone();
294 }
295 else if (rhs.mContentsHfv.getBuffer() != nullptr)
296 {
297 mContentsHfv.copyWithPadding(rhs.mContentsHfv);
298 }
299 else
300 {
301 // no body to copy
302 }
303 if (rhs.mForceTarget != nullptr)
304 {
305 mForceTarget = new Uri(*rhs.mForceTarget);
306 }
307
308 if (rhs.mSecurityAttributes.get())
309 {
310 if (!mSecurityAttributes.get())
311 {
312 SecurityAttributes* attr = new SecurityAttributes(*rhs.mSecurityAttributes);
313 mSecurityAttributes.reset(attr);
314 }
315 }
316 else
317 {
318 if (mSecurityAttributes.get())
319 {
320 mSecurityAttributes.reset();
321 }
322 }
323
324 for(std::vector<MessageDecorator*>::const_iterator i=rhs.mOutboundDecorators.begin(); i!=rhs.mOutboundDecorators.end();++i)
325 {
326 mOutboundDecorators.push_back((*i)->clone());
327 }
328}
329
330void
331SipMessage::freeMem(bool leaveResponseStuff)
332{
333 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
334 i != mUnknownHeaders.end(); ++i)
335 {
336 freeHfvl(i->second);
337 }
338
339 if (!leaveResponseStuff)
340 {
341 clearHeaders();
342
343 for (char* buffer : mBufferList)
344 {
345 delete [] buffer;
346 }
347 }
348
349 if (mStartLine)
350 {
351 mStartLine->~StartLine();
352 mStartLine = nullptr;
353 }
354
355 delete mContents;
356 delete mForceTarget;
357 delete mReason;
358
359 for (MessageDecorator* decorator : mOutboundDecorators)
360 {
361 delete decorator;
362 }
363}
364
365void
367{
368 mKnownHeaders.clearAndDispose([this](KnownHeaders::reference elem) noexcept { freeHfvl(elem.getValues()); });
369}
370
372SipMessage::make(const Data& data, bool isExternal)
373{
374 Tuple fakeWireTuple;
375 fakeWireTuple.setType(UDP);
376 SipMessage* msg = new SipMessage(isExternal ? &fakeWireTuple : nullptr);
377
378 size_t len = data.size();
379 char *buffer = new char[len + 5];
380
381 msg->addBuffer(buffer);
382 memcpy(buffer,data.data(), len);
383 MsgHeaderScanner msgHeaderScanner;
384 msgHeaderScanner.prepareForMessage(msg);
385
386 char *unprocessedCharPtr;
387 if (msgHeaderScanner.scanChunk(buffer, (unsigned int)len, &unprocessedCharPtr) != MsgHeaderScanner::scrEnd)
388 {
389 DebugLog(<<"Scanner rejecting buffer as unparsable / fragmented.");
390 DebugLog(<< data);
391 delete msg;
392 msg = nullptr;
393 return nullptr;
394 }
395
396 // no pp error
397 unsigned int used = (unsigned int)(unprocessedCharPtr - buffer);
398
399 if (used < len)
400 {
401 // body is present .. add it up.
402 // NB. The Sip Message uses an overlay (again)
403 // for the body. It ALSO expects that the body
404 // will be contiguous (of course).
405 // it doesn't need a new buffer in UDP b/c there
406 // will only be one datagram per buffer. (1:1 strict)
407
408 msg->setBody(buffer+used,uint32_t(len-used));
409 //DebugLog(<<"added " << len-used << " byte body");
410 }
411
412 return msg;
413}
414
415void
417{
418 for (KnownHeaders::reference info : mKnownHeaders)
419 {
420 HeaderFieldValueList* hfvl = info.getValues();
421 resip_assert(hfvl != nullptr);
422 if (!Headers::isMulti(info.getType()) && hfvl->parsedEmpty())
423 {
424 hfvl->push_back(nullptr, 0, false);
425 }
426
428 if (!pc)
429 {
430 pc = HeaderBase::getInstance(info.getType())->makeContainer(hfvl);
431 hfvl->setParserContainer(pc);
432 }
433
434 pc->parseAll();
435 }
436
437 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
438 i != mUnknownHeaders.end(); ++i)
439 {
440 ParserContainerBase* scs = i->second->getParserContainer();
441 if (!scs)
442 {
443 scs=makeParserContainer<StringCategory>(i->second,Headers::RESIP_DO_NOT_USE);
444 i->second->setParserContainer(scs);
445 }
446
447 scs->parseAll();
448 }
449
450 resip_assert(mStartLine != nullptr);
451
452 mStartLine->checkParsed();
453
454 getContents();
455}
456
457const Data&
459{
460 if (empty(h_Vias))
461 {
462 InfoLog (<< "Bad message with no Vias: " << *this);
463 throw Exception("No Via in message", __FILE__,__LINE__);
464 }
465
466 resip_assert(exists(h_Vias) && !header(h_Vias).empty());
467 if( exists(h_Vias) && header(h_Vias).front().exists(p_branch)
468 && header(h_Vias).front().param(p_branch).hasMagicCookie()
469 && (!header(h_Vias).front().param(p_branch).getTransactionId().empty())
470 )
471 {
472 return header(h_Vias).front().param(p_branch).getTransactionId();
473 }
474 else
475 {
476 if (mRFC2543TransactionId.empty())
477 {
478 compute2543TransactionHash();
479 }
480 return mRFC2543TransactionId;
481 }
482}
483
484void
485SipMessage::compute2543TransactionHash() const
486{
487 resip_assert (mRFC2543TransactionId.empty());
488
489 /* From rfc3261, 17.2.3
490 The INVITE request matches a transaction if the Request-URI, To tag,
491 From tag, Call-ID, CSeq, and top Via header field match those of the
492 INVITE request which created the transaction. In this case, the
493 INVITE is a retransmission of the original one that created the
494 transaction.
495
496 The ACK request matches a transaction if the Request-URI, From tag,
497 Call-ID, CSeq number (not the method), and top Via header field match
498 those of the INVITE request which created the transaction, and the To
499 tag of the ACK matches the To tag of the response sent by the server
500 transaction.
501
502 Matching is done based on the matching rules defined for each of those
503 header fields. Inclusion of the tag in the To header field in the ACK
504 matching process helps disambiguate ACK for 2xx from ACK for other
505 responses at a proxy, which may have forwarded both responses (This
506 can occur in unusual conditions. Specifically, when a proxy forked a
507 request, and then crashes, the responses may be delivered to another
508 proxy, which might end up forwarding multiple responses upstream). An
509 ACK request that matches an INVITE transaction matched by a previous
510 ACK is considered a retransmission of that previous ACK.
511
512 For all other request methods, a request is matched to a transaction
513 if the Request-URI, To tag, From tag, Call-ID, CSeq (including the
514 method), and top Via header field match those of the request that
515 created the transaction. Matching is done based on the matching
516 */
517
518 // If it is here and isn't a request, leave the transactionId empty, this
519 // will cause the Transaction to send it statelessly
520
521 if (isRequest())
522 {
523 DigestStream strm;
524 // See section 17.2.3 Matching Requests to Server Transactions in rfc 3261
525
526//#define VONAGE_FIX
527#ifndef VONAGE_FIX
528 strm << header(h_RequestLine).uri().scheme();
529 strm << header(h_RequestLine).uri().user();
530 strm << header(h_RequestLine).uri().host();
531 strm << header(h_RequestLine).uri().port();
532 strm << header(h_RequestLine).uri().password();
534#endif
535 if (!empty(h_Vias))
536 {
537 strm << header(h_Vias).front().protocolName();
538 strm << header(h_Vias).front().protocolVersion();
539 strm << header(h_Vias).front().transport();
540 strm << header(h_Vias).front().sentHost();
541 strm << header(h_Vias).front().sentPort();
542 strm << header(h_Vias).front().commutativeParameterHash();
543 }
544
545 if (header(h_From).exists(p_tag))
546 {
547 strm << header(h_From).param(p_tag);
548 }
549
550 // Only include the totag for non-invite requests
551 if (header(h_RequestLine).getMethod() != INVITE &&
552 header(h_RequestLine).getMethod() != ACK &&
553 header(h_RequestLine).getMethod() != CANCEL &&
554 header(h_To).exists(p_tag))
555 {
556 strm << header(h_To).param(p_tag);
557 }
558
559 strm << header(h_CallID).value();
560
561 if (header(h_RequestLine).getMethod() == ACK ||
562 header(h_RequestLine).getMethod() == CANCEL)
563 {
564 strm << INVITE;
565 strm << header(h_CSeq).sequence();
566 }
567 else
568 {
569 strm << header(h_CSeq).method();
570 strm << header(h_CSeq).sequence();
571 }
572
573 mRFC2543TransactionId = strm.getHex();
574 }
575 else
576 {
577 InfoLog (<< "Trying to compute a transaction id on a 2543 response. Drop the response");
578 DebugLog (<< *this);
579 throw Exception("Drop invalid 2543 response", __FILE__, __LINE__);
580 }
581}
582
583const Data&
585{
586 if(empty(h_Vias) ||
587 !header(h_Vias).front().exists(p_branch) ||
588 !header(h_Vias).front().param(p_branch).hasMagicCookie() ||
589 header(h_Vias).front().param(p_branch).getTransactionId().empty())
590 {
591 if (mRFC2543TransactionId.empty())
592 {
593 compute2543TransactionHash();
594 }
595 }
596 return mRFC2543TransactionId;
597}
598
599
600Data
602{
603 Data result;
604 DataStream strm(result);
605
606 // digest-string = addr-spec ":" addr-spec ":" callid ":" 1*DIGIT SP method ":"
607 // SIP-Date ":" [ addr-spec ] ":" message-body
608
609 strm << header(h_From).uri();
610 strm << Symbols::BAR;
611
612 strm << header(h_To).uri();
613 strm << Symbols::BAR;
614
615 strm << header(h_CallId).value();
616 strm << Symbols::BAR;
617
618 header(h_CSeq).sequence(); // force parsed
619 header(h_CSeq).encodeParsed( strm );
620 strm << Symbols::BAR;
621
622 // if there is no date, it will throw
623 if ( empty(h_Date) )
624 {
625 WarningLog( << "Computing Identity on message with no Date header" );
626 // TODO FIX - should it have a throw here ???? Help ???
627 }
628 header(h_Date).dayOfMonth(); // force it to be parsed
629 header(h_Date).encodeParsed( strm );
630 strm << Symbols::BAR;
631
632 if ( !empty(h_Contacts) )
633 {
634 if ( header(h_Contacts).front().isAllContacts() )
635 {
636 strm << Symbols::STAR;
637 }
638 else
639 {
640 strm << header(h_Contacts).front().uri();
641 }
642 }
643 strm << Symbols::BAR;
644
645 // bodies
646 if (mContents != nullptr)
647 {
648 mContents->encode(strm);
649 }
650 else if (mContentsHfv.getBuffer() != nullptr)
651 {
652 mContentsHfv.encode(strm);
653 }
654
655 strm.flush();
656
657 DebugLog( << "Identity Canonical String is: " << result );
658
659 return result;
660}
661
662
663void
665{
666 mRFC2543TransactionId = tid;
667}
668
671{
672 resip::MethodTypes res=UNKNOWN;
673 try
674 {
675 if(isRequest())
676 {
678 }
679 else if(isResponse())
680 {
681 res=header(h_CSeq).method();
682 }
683 else
684 {
685 resip_assert(0);
686 }
687 }
689 {
690 }
691
692 return res;
693}
694
695const Data&
697{
698 if(method()!=UNKNOWN)
699 {
700 return getMethodName(method());
701 }
702 else
703 {
704 try
705 {
706 if(isRequest())
707 {
709 }
710 else if(isResponse())
711 {
712 return header(h_CSeq).unknownMethodName();
713 }
714 else
715 {
716 resip_assert(0);
717 }
718 }
720 {
721 }
722 }
723 return Data::Empty;
724}
725
726static const Data requestEB("SipReq: ");
727static const Data responseEB("SipResp: ");
728static const Data tidEB(" tid=");
729static const Data contactEB(" contact=");
730static const Data cseqEB(" cseq=");
731static const Data slashEB(" / ");
732static const Data wireEB(" from(wire)");
733static const Data ftuEB(" from(tu)");
734static const Data tlsdEB(" tlsd=");
736SipMessage::encodeBrief(EncodeStream& str) const
737{
738 if (isRequest())
739 {
740 str << requestEB;
742 if (meth != UNKNOWN)
743 {
744 str << getMethodName(meth);
745 }
746 else
747 {
749 }
750
751 str << Symbols::SPACE;
752 str << header(h_RequestLine).uri().getAor();
753 }
754 else if (isResponse())
755 {
756 str << responseEB;
757 str << header(h_StatusLine).responseCode();
758 }
759 if (!empty(h_Vias))
760 {
761 str << tidEB;
762 try
763 {
764 str << getTransactionId();
765 }
766 catch(BaseException&) // Could be SipMessage::Exception or ParseException
767 {
768 str << "BAD-VIA";
769 }
770 }
771 else
772 {
773 str << " NO-VIAS ";
774 }
775
776 str << cseqEB;
777 str << header(h_CSeq);
778
779 try
780 {
781 if (!empty(h_Contacts))
782 {
783 str << contactEB;
784 str << header(h_Contacts).front().uri().getAor();
785 }
786 }
788 {
789 str << " MALFORMED CONTACT ";
790 }
791
792 str << slashEB;
793 str << header(h_CSeq).sequence();
794 str << (mIsExternal ? wireEB : ftuEB);
795 if (!mTlsDomain.empty())
796 {
797 str << tlsdEB << mTlsDomain;
798 }
799
800 return str;
801}
802
803bool
805{
806 resip_assert(mRequest || mResponse);
807 return ((mIsExternal && mResponse) || (!mIsExternal && mRequest));
808}
809
811SipMessage::encode(EncodeStream& str) const
812{
813 return encode(str, false);
814}
815
817SipMessage::encodeSipFrag(EncodeStream& str) const
818{
819 return encode(str, true);
820}
821
822// dynamic_cast &str to DataStream* to avoid CountStream?
823
825SipMessage::encode(EncodeStream& str, bool isSipFrag) const
826{
827 if (mStartLine != nullptr)
828 {
829 mStartLine->encode(str);
830 str << "\r\n";
831 }
832
833 Data contents;
834 if (mContents != nullptr)
835 {
836 oDataStream temp(contents);
837 mContents->encode(temp);
838 }
839 else if (mContentsHfv.getBuffer() != nullptr)
840 {
841#if 0
842 // !bwc! This causes an additional copy; sure would be nice to have a way
843 // to get a data to take on a buffer with Data::Share _after_ construction
844 contents.append(mContentsHfv.getBuffer(), mContentsHfv.getLength());
845#else
846 // .kw. Your wish is granted
847 mContentsHfv.toShareData(contents);
848#endif
849 }
850
851 for (KnownHeaders::OrderedView::const_reference info : mKnownHeaders.ordered())
852 {
853 if (info.getType() != Headers::ContentLength) // !dlb! hack...
854 {
855 info.getValues()->encode(info.getType(), str);
856 }
857 }
858
859 for (UnknownHeaders::const_iterator i = mUnknownHeaders.begin();
860 i != mUnknownHeaders.end(); ++i)
861 {
862 i->second->encode(i->first, str);
863 }
864
865 if(!isSipFrag || !contents.empty())
866 {
867 str << "Content-Length: " << contents.size() << "\r\n";
868 }
869
870 str << Symbols::CRLF;
871
872 str << contents;
873 return str;
874}
875
877SipMessage::encodeSingleHeader(Headers::Type type, EncodeStream& str) const
878{
879 auto it = mKnownHeaders.find(type);
880 if (it != mKnownHeaders.end())
881 {
882 it->getValues()->encode(type, str);
883 }
884 return str;
885}
886
888SipMessage::encodeEmbedded(EncodeStream& str) const
889{
890 bool first = true;
891 for (KnownHeaders::OrderedView::const_reference info : mKnownHeaders.ordered())
892 {
893 if (info.getType() != Headers::ContentLength)
894 {
895 if (first)
896 {
897 str << Symbols::QUESTION;
898 first = false;
899 }
900 else
901 {
902 str << Symbols::AMPERSAND;
903 }
904 info.getValues()->encodeEmbedded(Headers::getHeaderName(info.getType()), str);
905 }
906 }
907
908 for (UnknownHeaders::const_iterator i = mUnknownHeaders.begin();
909 i != mUnknownHeaders.end(); ++i)
910 {
911 if (first)
912 {
913 str << Symbols::QUESTION;
914 first = false;
915 }
916 else
917 {
918 str << Symbols::AMPERSAND;
919 }
920 i->second->encodeEmbedded(i->first, str);
921 }
922
923 if (mContents != nullptr || mContentsHfv.getBuffer() != nullptr)
924 {
925 if (first)
926 {
927 str << Symbols::QUESTION;
928 }
929 else
930 {
931 str << Symbols::AMPERSAND;
932 }
933 str << "body=";
934 Data contents;
935 // !dlb! encode escaped for characters
936 // .kw. what does that mean? what needs to be escaped?
937 if (mContents != nullptr)
938 {
939 DataStream s(contents);
940 mContents->encode(s);
941 }
942 else
943 {
944 // .kw. Early code did:
945 // DataStream s(contents);
946 // mContentsHfv->encode(str);
947 // str << Embedded::encode(contents);
948 // .kw. which I think is buggy b/c Hfv was written directly
949 // to str and skipped the encode step via contents
950 mContentsHfv.toShareData(contents);
951 }
952 str << Embedded::encode(contents);
953 }
954 return str;
955}
956
957void
959{
960 mBufferList.push_back(buf);
961}
962
963void
965{
966 if (len >= 4 && !strncasecmp(st,"SIP/",4))
967 {
968 // Response
969 mStartLine = new (mStartLineMem) StatusLine(st, len);
971 mResponse = true;
972 }
973 else
974 {
975 // Request
976 mStartLine = new (mStartLineMem) RequestLine(st, len);
978 mRequest = true;
979 }
980
981
982// .bwc. This stuff is so needlessly complicated. Much, much simpler, faster,
983// and more robust code above.
984// ParseBuffer pb(st, len);
985// const char* start;
986// start = pb.skipWhitespace();
987// pb.skipNonWhitespace();
988// MethodTypes method = getMethodType(start, pb.position() - start);
989// if (method == UNKNOWN) //probably a status line
990// {
991// start = pb.skipChar(Symbols::SPACE[0]);
992// pb.skipNonWhitespace();
993// if ((pb.position() - start) == 3)
994// {
995// mStartLine = new (mStartLineMem) StatusLine(st, len ,Headers::NONE);
996// //!dcm! should invoke the statusline parser here once it does limited validation
997// mResponse = true;
998// }
999// }
1000// if (!mResponse)
1001// {
1002// mStartLine = new (mStartLineMem) RequestLine(st, len, Headers::NONE);
1003// //!dcm! should invoke the responseline parser here once it does limited validation
1004// mRequest = true;
1005// }
1006}
1007
1008void
1009SipMessage::setBody(const char* start, uint32_t len)
1010{
1012 {
1013 if(exists(h_ContentLength))
1014 {
1015 try
1016 {
1017 const_header(h_ContentLength).checkParsed();
1018 }
1019 catch(resip::ParseException& e)
1020 {
1021 if(!mReason)
1022 {
1023 mReason=new Data;
1024 }
1025
1026 if(mInvalid)
1027 {
1028 mReason->append(",",1);
1029 }
1030
1031 mInvalid=true;
1032 mReason->append("Malformed Content-Length",24);
1033 InfoLog(<< "Malformed Content-Length. Ignoring. " << e);
1034 header(h_ContentLength).value()=len;
1035 }
1036
1037 uint32_t contentLength=const_header(h_ContentLength).value();
1038
1039 if(len > contentLength)
1040 {
1041 InfoLog(<< (len-contentLength) << " extra bytes after body. Ignoring these bytes.");
1042 }
1043 else if(len < contentLength)
1044 {
1045 InfoLog(<< "Content Length (" << contentLength << ") is "
1046 << (contentLength-len) << " bytes larger than body (" << len << ")!"
1047 << " (We are supposed to 400 this) ");
1048
1049 if(!mReason)
1050 {
1051 mReason=new Data;
1052 }
1053
1054 if(mInvalid)
1055 {
1056 mReason->append(",",1);
1057 }
1058
1059 mInvalid=true;
1060 mReason->append("Bad Content-Length (larger than datagram)",41);
1061 header(h_ContentLength).value()=len;
1062 contentLength=len;
1063
1064 }
1065
1066 mContentsHfv.init(start,contentLength, false);
1067 }
1068 else
1069 {
1070 InfoLog(<< "Message has a body, but no Content-Length header.");
1071 mContentsHfv.init(start,len, false);
1072 }
1073 }
1074 else
1075 {
1076 mContentsHfv.init(start,len, false);
1077 }
1078}
1079
1080void
1082{
1083 setContents(unique_ptr<Contents>());
1084 mContentsHfv = body;
1085}
1086
1087
1088void
1089SipMessage::setContents(unique_ptr<Contents> contents)
1090{
1091 Contents* contentsP = contents.release();
1092
1093 delete mContents;
1094 mContents = nullptr;
1095 mContentsHfv.clear();
1096
1097 if (contentsP == nullptr)
1098 {
1099 // The semantics of setContents(0) are to delete message contents
1100 remove(h_ContentType);
1101 remove(h_ContentDisposition);
1102 remove(h_ContentTransferEncoding);
1103 remove(h_ContentLanguages);
1104 return;
1105 }
1106
1107 mContents = contentsP;
1108
1109 // copy contents headers into message
1110 if (mContents->exists(h_ContentDisposition))
1111 {
1112 header(h_ContentDisposition) = mContents->header(h_ContentDisposition);
1113 }
1114 if (mContents->exists(h_ContentTransferEncoding))
1115 {
1116 header(h_ContentTransferEncoding) = mContents->header(h_ContentTransferEncoding);
1117 }
1118 if (mContents->exists(h_ContentLanguages))
1119 {
1120 header(h_ContentLanguages) = mContents->header(h_ContentLanguages);
1121 }
1122 if (mContents->exists(h_ContentType))
1123 {
1124 header(h_ContentType) = mContents->header(h_ContentType);
1125 resip_assert( header(h_ContentType).type() == mContents->getType().type() );
1126 resip_assert( header(h_ContentType).subType() == mContents->getType().subType() );
1127 }
1128 else
1129 {
1130 header(h_ContentType) = mContents->getType();
1131 }
1132}
1133
1134void
1136{
1137 if (contents)
1138 {
1139 setContents(unique_ptr<Contents>(contents->clone()));
1140 }
1141 else
1142 {
1143 setContents(unique_ptr<Contents>());
1144 }
1145}
1146
1147Contents*
1149{
1150 if (mContents == nullptr && mContentsHfv.getBuffer() != nullptr)
1151 {
1152 if (empty(h_ContentType) ||
1153 !const_header(h_ContentType).isWellFormed())
1154 {
1155 StackLog(<< "SipMessage::getContents: ContentType header does not exist - implies no contents");
1156 return 0;
1157 }
1158 DebugLog(<< "SipMessage::getContents: "
1159 << const_header(h_ContentType).type()
1160 << "/"
1161 << const_header(h_ContentType).subType());
1162
1164 {
1165 InfoLog(<< "SipMessage::getContents: got content type ("
1166 << const_header(h_ContentType).type()
1167 << "/"
1168 << const_header(h_ContentType).subType()
1169 << ") that is not known, "
1170 << "returning as opaque application/octet-stream");
1172 }
1173 else
1174 {
1175 mContents = ContentsFactoryBase::getFactoryMap()[const_header(h_ContentType)]->create(mContentsHfv, const_header(h_ContentType));
1176 }
1177 resip_assert( mContents );
1178
1179 // copy contents headers into the contents
1180 if (!empty(h_ContentDisposition))
1181 {
1182 mContents->header(h_ContentDisposition) = const_header(h_ContentDisposition);
1183 }
1184 if (!empty(h_ContentTransferEncoding))
1185 {
1186 mContents->header(h_ContentTransferEncoding) = const_header(h_ContentTransferEncoding);
1187 }
1188 if (!empty(h_ContentLanguages))
1189 {
1190 mContents->header(h_ContentLanguages) = const_header(h_ContentLanguages);
1191 }
1192 if (!empty(h_ContentType))
1193 {
1194 mContents->header(h_ContentType) = const_header(h_ContentType);
1195 }
1196 // !dlb! Content-Transfer-Encoding?
1197 }
1198 return mContents;
1199}
1200
1201unique_ptr<Contents>
1203{
1204 Contents* c=getContents();
1205 // .bwc. unique_ptr owns the Contents. No other references allowed!
1206 unique_ptr<Contents> ret(c ? c->clone() : nullptr);
1207 setContents(unique_ptr<Contents>());
1208
1209 if (ret != nullptr && !ret->isWellFormed())
1210 {
1211 ret.reset();
1212 }
1213
1214 return ret;
1215}
1216
1217// unknown header interface
1218const StringCategories&
1219SipMessage::header(const ExtensionHeader& headerName) const
1220{
1221 ParserContainer<StringCategory>* parser = nullptr;
1222 for (UnknownHeaders::const_iterator i = mUnknownHeaders.begin();
1223 i != mUnknownHeaders.end(); ++i)
1224 {
1225 if (isEqualNoCase(i->first, headerName.getName()))
1226 {
1227 HeaderFieldValueList* hfvs = i->second;
1228 if (hfvs->getParserContainer() == nullptr)
1229 {
1230 SipMessage* nc_this(const_cast<SipMessage*>(this));
1231 hfvs->setParserContainer(nc_this->makeParserContainer<StringCategory>(hfvs, Headers::RESIP_DO_NOT_USE));
1232 }
1233 parser = dynamic_cast<ParserContainer<StringCategory>*>(hfvs->getParserContainer());
1234 break;
1235 }
1236 }
1237
1238 if (!parser)
1239 {
1240 throw Exception("Missing extension header", __FILE__, __LINE__);
1241 }
1242
1243 return *parser;
1244}
1245
1248{
1249 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
1250 i != mUnknownHeaders.end(); ++i)
1251 {
1252 if (isEqualNoCase(i->first, headerName.getName()))
1253 {
1254 HeaderFieldValueList* hfvs = i->second;
1255 if (hfvs->getParserContainer() == nullptr)
1256 {
1257 hfvs->setParserContainer(makeParserContainer<StringCategory>(hfvs, Headers::RESIP_DO_NOT_USE));
1258 }
1259 return *dynamic_cast<ParserContainer<StringCategory>*>(hfvs->getParserContainer());
1260 }
1261 }
1262
1263 // create the list empty
1264 HeaderFieldValueList* hfvs = getEmptyHfvl();
1265 hfvs->setParserContainer(makeParserContainer<StringCategory>(hfvs, Headers::RESIP_DO_NOT_USE));
1266 mUnknownHeaders.push_back(make_pair(headerName.getName(), hfvs));
1267 return *dynamic_cast<ParserContainer<StringCategory>*>(hfvs->getParserContainer());
1268}
1269
1270bool
1272{
1273 for (UnknownHeaders::const_iterator i = mUnknownHeaders.begin();
1274 i != mUnknownHeaders.end(); ++i)
1275 {
1276 if (isEqualNoCase(i->first, symbol.getName()))
1277 {
1278 return true;
1279 }
1280 }
1281 return false;
1282}
1283
1284void
1286{
1287 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
1288 i != mUnknownHeaders.end(); ++i)
1289 {
1290 if (isEqualNoCase(i->first, headerName.getName()))
1291 {
1292 freeHfvl(i->second);
1293 mUnknownHeaders.erase(i);
1294 return;
1295 }
1296 }
1297}
1298
1299void
1300SipMessage::addHeader(Headers::Type header, const char* headerName, uint32_t headerNameLen,
1301 const char* value, uint32_t valueLen)
1302{
1303 if (header != Headers::UNKNOWN)
1304 {
1306 HeaderFieldValueList* hfvl = ensureHeaders(header);
1307
1309 {
1310 if (valueLen > 0)
1311 {
1312 hfvl->push_back(value, valueLen, false);
1313 }
1314 }
1315 else
1316 {
1317#ifdef PEDANTIC_STACK
1318 if (hfvl->size() == 1)
1319 {
1320 if (!mReason)
1321 {
1322 mReason = new Data;
1323 }
1324
1325 if (mInvalid)
1326 {
1327 mReason->append(",", 1);
1328 }
1329 mInvalid = true;
1330 mReason->append("Multiple values in single-value header ", 39);
1331 (*mReason) += Headers::getHeaderName(header);
1332 return;
1333 }
1334#endif
1335 if (hfvl->empty())
1336 {
1337 hfvl->push_back(value, valueLen, false);
1338 }
1339 }
1340 }
1341 else
1342 {
1343 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
1344 i != mUnknownHeaders.end(); ++i)
1345 {
1346 if (i->first.size() == headerNameLen &&
1347 strncasecmp(i->first.data(), headerName, headerNameLen) == 0)
1348 {
1349 // add to end of list
1350 if (valueLen > 0)
1351 {
1352 i->second->push_back(value, valueLen, false);
1353 }
1354 return;
1355 }
1356 }
1357
1358 // didn't find it, add an entry
1359 HeaderFieldValueList *hfvs = getEmptyHfvl();
1360 if (valueLen > 0)
1361 {
1362 hfvs->push_back(value, valueLen, false);
1363 }
1364 mUnknownHeaders.push_back(pair<Data, HeaderFieldValueList*>(Data(headerName, headerNameLen),
1365 hfvs));
1366 }
1367}
1368
1371{
1373 if (mStartLine == nullptr)
1374 {
1375 mStartLine = new (mStartLineMem) RequestLine;
1376 mRequest = true;
1377 }
1378 return *static_cast<RequestLine*>(mStartLine);
1379}
1380
1381const RequestLine&
1383{
1385 if (mStartLine == nullptr)
1386 {
1387 // request line missing
1388 resip_assert(false);
1389 }
1390 return *static_cast<RequestLine*>(mStartLine);
1391}
1392
1393StatusLine&
1395{
1397 if (mStartLine == nullptr)
1398 {
1399 mStartLine = new (mStartLineMem) StatusLine;
1400 mResponse = true;
1401 }
1402 return *static_cast<StatusLine*>(mStartLine);
1403}
1404
1405const StatusLine&
1407{
1409 if (mStartLine == nullptr)
1410 {
1411 // status line missing
1412 resip_assert(false);
1413 }
1414 return *static_cast<StatusLine*>(mStartLine);
1415}
1416
1418SipMessage::ensureHeaders(Headers::Type type)
1419{
1420 return mKnownHeaders.insert(type, [this] { return getEmptyHfvl(); })->getValues();
1421}
1422
1424SipMessage::ensureHeaders(Headers::Type type) const
1425{
1426 auto it = mKnownHeaders.find(type);
1427 if (it == mKnownHeaders.end())
1428 {
1429 throwHeaderMissing(type);
1430 }
1431 return it->getValues();
1432}
1433
1435SipMessage::ensureHeader(Headers::Type type)
1436{
1437 HeaderFieldValueList* hfvl = ensureHeaders(type);
1438 if (hfvl->empty())
1439 hfvl->push_back(nullptr, 0, false);
1440
1441 return hfvl;
1442}
1443
1445SipMessage::ensureHeader(Headers::Type type) const
1446{
1447 HeaderFieldValueList* hfvl = ensureHeaders(type);
1448 if (hfvl->empty())
1449 hfvl->push_back(nullptr, 0, false);
1450
1451 return hfvl;
1452}
1453
1454void
1455SipMessage::throwHeaderMissing(Headers::Type type) const
1456{
1457 // header missing
1458 // assert(false);
1459 InfoLog( << "Missing Header [" << Headers::getHeaderName(type) << "]");
1460 DebugLog (<< *this);
1461 throw Exception("Missing header " + Headers::getHeaderName(type), __FILE__, __LINE__);
1462}
1463
1464// type safe header accessors
1465bool
1466SipMessage::exists(const HeaderBase& headerType) const
1467{
1468 return mKnownHeaders.find(headerType.getTypeNum()) != mKnownHeaders.end();
1469};
1470
1471bool
1472SipMessage::empty(const HeaderBase& headerType) const
1473{
1474 auto it = mKnownHeaders.find(headerType.getTypeNum());
1475 return it == mKnownHeaders.end() || it->getValues()->parsedEmpty();
1476}
1477
1478void
1480{
1481 auto it = mKnownHeaders.find(type);
1482 if (it != mKnownHeaders.end())
1483 mKnownHeaders.erase(it);
1484};
1485
1486#ifndef PARTIAL_TEMPLATE_SPECIALIZATION
1487
1488#undef defineHeader
1489#define defineHeader(_header, _name, _type, _rfc) \
1490const H_##_header::Type& \
1491SipMessage::header(const H_##_header& headerType) const \
1492{ \
1493 HeaderFieldValueList* hfvs = ensureHeader(headerType.getTypeNum()); \
1494 if (hfvs->getParserContainer() == nullptr) \
1495 { \
1496 SipMessage* nc_this(const_cast<SipMessage*>(this)); \
1497 hfvs->setParserContainer(nc_this->makeParserContainer<H_##_header::Type>(hfvs, headerType.getTypeNum())); \
1498 } \
1499 return static_cast<ParserContainer<H_##_header::Type>*>(hfvs->getParserContainer())->front(); \
1500} \
1501 \
1502H_##_header::Type& \
1503SipMessage::header(const H_##_header& headerType) \
1504{ \
1505 HeaderFieldValueList* hfvs = ensureHeader(headerType.getTypeNum()); \
1506 if (hfvs->getParserContainer() == nullptr) \
1507 { \
1508 hfvs->setParserContainer(makeParserContainer<H_##_header::Type>(hfvs, headerType.getTypeNum())); \
1509 } \
1510 return static_cast<ParserContainer<H_##_header::Type>*>(hfvs->getParserContainer())->front(); \
1511}
1512
1513#undef defineMultiHeader
1514#define defineMultiHeader(_header, _name, _type, _rfc) \
1515const H_##_header##s::Type& \
1516SipMessage::header(const H_##_header##s& headerType) const \
1517{ \
1518 HeaderFieldValueList* hfvs = ensureHeaders(headerType.getTypeNum()); \
1519 if (hfvs->getParserContainer() == nullptr) \
1520 { \
1521 SipMessage* nc_this(const_cast<SipMessage*>(this)); \
1522 hfvs->setParserContainer(nc_this->makeParserContainer<H_##_header##s::ContainedType>(hfvs, headerType.getTypeNum())); \
1523 } \
1524 return *static_cast<H_##_header##s::Type*>(hfvs->getParserContainer()); \
1525} \
1526 \
1527H_##_header##s::Type& \
1528SipMessage::header(const H_##_header##s& headerType) \
1529{ \
1530 HeaderFieldValueList* hfvs = ensureHeaders(headerType.getTypeNum()); \
1531 if (hfvs->getParserContainer() == nullptr) \
1532 { \
1533 hfvs->setParserContainer(makeParserContainer<H_##_header##s::ContainedType>(hfvs, headerType.getTypeNum())); \
1534 } \
1535 return *static_cast<H_##_header##s::Type*>(hfvs->getParserContainer()); \
1536}
1537
1538defineHeader(ContentDisposition, "Content-Disposition", Token, "RFC 3261");
1539defineHeader(ContentEncoding, "Content-Encoding", Token, "RFC 3261");
1540defineHeader(MIMEVersion, "Mime-Version", Token, "RFC 3261");
1541defineHeader(Priority, "Priority", Token, "RFC 3261");
1542defineHeader(Event, "Event", Token, "RFC 3265");
1543defineHeader(SubscriptionState, "Subscription-State", Token, "RFC 3265");
1544defineHeader(SIPETag, "SIP-ETag", Token, "RFC 3903");
1545defineHeader(SIPIfMatch, "SIP-If-Match", Token, "RFC 3903");
1546defineHeader(ContentId, "Content-ID", Token, "RFC 2045");
1547defineMultiHeader(AllowEvents, "Allow-Events", Token, "RFC 3265");
1548defineMultiHeader(Identity, "Identity", IdentityCategory, "RFC 8224"); // Originally defined in RFC 4474 as a single header, but later modified by RFC8224 to be a multiheader
1549defineMultiHeader(AcceptEncoding, "Accept-Encoding", Token, "RFC 3261");
1550defineMultiHeader(AcceptLanguage, "Accept-Language", Token, "RFC 3261");
1551defineMultiHeader(Allow, "Allow", Token, "RFC 3261");
1552defineMultiHeader(ContentLanguage, "Content-Language", Token, "RFC 3261");
1553defineMultiHeader(ProxyRequire, "Proxy-Require", Token, "RFC 3261");
1554defineMultiHeader(Require, "Require", Token, "RFC 3261");
1555defineMultiHeader(Supported, "Supported", Token, "RFC 3261");
1556defineMultiHeader(Unsupported, "Unsupported", Token, "RFC 3261");
1557defineMultiHeader(SecurityClient, "Security-Client", Token, "RFC 3329");
1558defineMultiHeader(SecurityServer, "Security-Server", Token, "RFC 3329");
1559defineMultiHeader(SecurityVerify, "Security-Verify", Token, "RFC 3329");
1560defineMultiHeader(RequestDisposition, "Request-Disposition", Token, "RFC 3841");
1561defineMultiHeader(Reason, "Reason", Token, "RFC 3326");
1562defineMultiHeader(Privacy, "Privacy", PrivacyCategory, "RFC 3323");
1563defineMultiHeader(PMediaAuthorization, "P-Media-Authorization", Token, "RFC 3313");
1564defineHeader(ReferSub, "Refer-Sub", Token, "RFC 4488");
1565defineHeader(AnswerMode, "Answer-Mode", Token, "draft-ietf-answermode-01");
1566defineHeader(PrivAnswerMode, "Priv-Answer-Mode", Token, "draft-ietf-answermode-01");
1567
1568defineMultiHeader(Accept, "Accept", Mime, "RFC 3261");
1569defineHeader(ContentType, "Content-Type", Mime, "RFC 3261");
1570
1571defineMultiHeader(CallInfo, "Call-Info", GenericUri, "RFC 3261");
1572defineMultiHeader(AlertInfo, "Alert-Info", GenericUri, "RFC 3261");
1573defineMultiHeader(ErrorInfo, "Error-Info", GenericUri, "RFC 3261");
1574defineHeader(IdentityInfo, "Identity-Info", GenericUri, "RFC 4474");
1575
1576defineMultiHeader(RecordRoute, "Record-Route", NameAddr, "RFC 3261");
1577defineMultiHeader(Route, "Route", NameAddr, "RFC 3261");
1578defineMultiHeader(Contact, "Contact", NameAddr, "RFC 3261");
1579defineHeader(From, "From", NameAddr, "RFC 3261");
1580defineHeader(To, "To", NameAddr, "RFC 3261");
1581defineHeader(ReplyTo, "Reply-To", NameAddr, "RFC 3261");
1582defineHeader(ReferTo, "Refer-To", NameAddr, "RFC 3515");
1583defineHeader(ReferredBy, "Referred-By", NameAddr, "RFC 3892");
1584defineMultiHeader(Path, "Path", NameAddr, "RFC 3327");
1585defineMultiHeader(AcceptContact, "Accept-Contact", NameAddr, "RFC 3841");
1586defineMultiHeader(RejectContact, "Reject-Contact", NameAddr, "RFC 3841");
1587defineMultiHeader(PAssertedIdentity, "P-Asserted-Identity", NameAddr, "RFC 3325");
1588defineMultiHeader(PPreferredIdentity, "P-Preferred-Identity", NameAddr, "RFC 3325");
1589defineHeader(PCalledPartyId, "P-Called-Party-ID", NameAddr, "RFC 3455");
1590defineMultiHeader(PAssociatedUri, "P-Associated-URI", NameAddr, "RFC 3455");
1591defineMultiHeader(ServiceRoute, "Service-Route", NameAddr, "RFC 3608");
1592
1593defineHeader(ContentTransferEncoding, "Content-Transfer-Encoding", StringCategory, "RFC ?");
1594defineHeader(Organization, "Organization", StringCategory, "RFC 3261");
1595defineHeader(SecWebSocketKey, "Sec-WebSocket-Key", StringCategory, "RFC 6455");
1596defineHeader(SecWebSocketKey1, "Sec-WebSocket-Key1", StringCategory, "draft-hixie- thewebsocketprotocol-76");
1597defineHeader(SecWebSocketKey2, "Sec-WebSocket-Key2", StringCategory, "draft-hixie- thewebsocketprotocol-76");
1598defineHeader(Origin, "Origin", StringCategory, "draft-hixie- thewebsocketprotocol-76");
1599defineHeader(Host, "Host", StringCategory, "draft-hixie- thewebsocketprotocol-76");
1600defineHeader(SecWebSocketAccept, "Sec-WebSocket-Accept", StringCategory, "RFC 6455");
1602defineHeader(Server, "Server", StringCategory, "RFC 3261");
1603defineHeader(Subject, "Subject", StringCategory, "RFC 3261");
1604defineHeader(UserAgent, "User-Agent", StringCategory, "RFC 3261");
1605defineHeader(Timestamp, "Timestamp", StringCategory, "RFC 3261");
1606
1607defineHeader(ContentLength, "Content-Length", UInt32Category, "RFC 3261");
1608defineHeader(MaxForwards, "Max-Forwards", UInt32Category, "RFC 3261");
1609defineHeader(MinExpires, "Min-Expires", Uint32Category, "RFC 3261");
1610defineHeader(RSeq, "RSeq", UInt32Category, "RFC 3261");
1611
1612// !dlb! this one is not quite right -- can have (comment) after field value
1613defineHeader(RetryAfter, "Retry-After", UInt32Category, "RFC 3261");
1614defineHeader(FlowTimer, "Flow-Timer", UInt32Category, "RFC 5626");
1615
1616defineHeader(Expires, "Expires", ExpiresCategory, "RFC 3261");
1617defineHeader(SessionExpires, "Session-Expires", ExpiresCategory, "RFC 4028");
1618defineHeader(MinSE, "Min-SE", ExpiresCategory, "RFC 4028");
1619
1620defineHeader(CallID, "Call-ID", CallID, "RFC 3261");
1621defineHeader(Replaces, "Replaces", CallID, "RFC 3891");
1622defineHeader(InReplyTo, "In-Reply-To", CallID, "RFC 3261");
1623defineHeader(Join, "Join", CallId, "RFC 3911");
1624defineHeader(TargetDialog, "Target-Dialog", CallId, "RFC 4538");
1625
1626defineHeader(AuthenticationInfo, "Authentication-Info", Auth, "RFC 3261");
1627defineMultiHeader(Authorization, "Authorization", Auth, "RFC 3261");
1628defineMultiHeader(ProxyAuthenticate, "Proxy-Authenticate", Auth, "RFC 3261");
1629defineMultiHeader(ProxyAuthorization, "Proxy-Authorization", Auth, "RFC 3261");
1630defineMultiHeader(WWWAuthenticate, "Www-Authenticate", Auth, "RFC 3261");
1631
1632defineHeader(CSeq, "CSeq", CSeqCategory, "RFC 3261");
1633defineHeader(Date, "Date", DateCategory, "RFC 3261");
1634defineMultiHeader(Warning, "Warning", WarningCategory, "RFC 3261");
1635defineMultiHeader(Via, "Via", Via, "RFC 3261");
1636defineHeader(RAck, "RAck", RAckCategory, "RFC 3262");
1637defineMultiHeader(RemotePartyId, "Remote-Party-ID", NameAddr, "draft-ietf-sip-privacy-04"); // ?bwc? Not in 3323, should we keep?
1638defineMultiHeader(HistoryInfo, "History-Info", NameAddr, "RFC 4244");
1639defineMultiHeader(Diversion, "Diversion", NameAddr, "RFC 5806");
1640
1641defineMultiHeader(PAccessNetworkInfo, "P-Access-Network-Info", Token, "RFC 7315"); // section 5.4.
1642defineHeader(PChargingVector, "P-Charging-Vector", Token, "RFC 3455");
1643defineHeader(PChargingFunctionAddresses, "P-Charging-Function-Addresses", Token, "RFC 3455");
1644defineMultiHeader(PVisitedNetworkID, "P-Visited-Network-ID", TokenOrQuotedStringCategory, "RFC 3455");
1645
1646defineMultiHeader(UserToUser, "User-to-User", TokenOrQuotedStringCategory, "draft-ietf-cuss-sip-uui-17");
1647
1648#endif
1649
1652{
1653 auto it = mKnownHeaders.find(headerType);
1654 if (it != mKnownHeaders.end())
1655 {
1656 return it->getValues();
1657 }
1658
1659 return nullptr;
1660}
1661
1662void
1664{
1665 auto it = mKnownHeaders.find(headerType);
1666 if (it != mKnownHeaders.end())
1667 {
1668 *it->getValues() = *hfvs;
1669 }
1670 else
1671 {
1672 bool constructed = false;
1673 it = mKnownHeaders.insert(headerType, [&]
1674 {
1675 constructed = true;
1676 return getCopyHfvl(*hfvs);
1677 });
1678 if (!constructed)
1679 {
1680 // A previously erased element was reused
1681 *it->getValues() = *hfvs;
1682 }
1683 }
1684
1685 if(!Headers::isMulti(headerType) && it->getValues()->parsedEmpty())
1686 {
1687 it->getValues()->push_back(nullptr, 0, false);
1688 }
1689}
1690
1691void
1693{
1694 if (mForceTarget)
1695 {
1696 *mForceTarget = uri;
1697 }
1698 else
1699 {
1700 mForceTarget = new Uri(uri);
1701 }
1702}
1703
1704void
1706{
1707 delete mForceTarget;
1708 mForceTarget = nullptr;
1709}
1710
1711const Uri&
1713{
1714 resip_assert(mForceTarget != nullptr);
1715 return *mForceTarget;
1716}
1717
1718bool
1720{
1721 return (mForceTarget != nullptr);
1722}
1723
1724SipMessage&
1726{
1727 header(h_RequestLine).uri() = source;
1729
1730 if (source.exists(p_method))
1731 {
1732 header(h_RequestLine).method() = getMethodType(source.param(p_method));
1733 header(h_RequestLine).uri().remove(p_method);
1734 }
1735
1736 //19.1.5
1737 //dangerous headers not included in merge:
1738 // From, Call-ID, Cseq, Via, Record Route, Route, Accept, Accept-Encoding,
1739 // Accept-Langauge, Allow, Contact, Organization, Supported, User-Agent
1740
1741 //from the should-verify section, remove for now, some never seem to make
1742 //sense:
1743 // Content-Encoding, Content-Language, Content-Length, Content-Type, Date,
1744 // Mime-Version, and TimeStamp
1745
1746 if (source.hasEmbedded())
1747 {
1748 h_AuthenticationInfo.merge(*this, source.embedded());
1749 h_ContentTransferEncoding.merge(*this, source.embedded());
1750 h_Event.merge(*this, source.embedded());
1751 h_Expires.merge(*this, source.embedded());
1752 h_SessionExpires.merge(*this, source.embedded());
1753 h_MinSE.merge(*this, source.embedded());
1754 h_InReplyTo.merge(*this, source.embedded());
1755 h_MaxForwards.merge(*this, source.embedded());
1756 h_MinExpires.merge(*this, source.embedded());
1757 h_Priority.merge(*this, source.embedded());
1758 h_ReferTo.merge(*this, source.embedded());
1759 h_ReferredBy.merge(*this, source.embedded());
1760 h_Replaces.merge(*this, source.embedded());
1761 h_ReplyTo.merge(*this, source.embedded());
1762 h_RetryAfter.merge(*this, source.embedded());
1763 h_Server.merge(*this, source.embedded());
1764 h_SIPETag.merge(*this, source.embedded());
1765 h_SIPIfMatch.merge(*this, source.embedded());
1766 h_Subject.merge(*this, source.embedded());
1767 h_SubscriptionState.merge(*this, source.embedded());
1768 h_To.merge(*this, source.embedded());
1769 h_Warnings.merge(*this, source.embedded());
1770
1771 h_SecurityClients.merge(*this, source.embedded());
1772 h_SecurityServers.merge(*this, source.embedded());
1773 h_SecurityVerifys.merge(*this, source.embedded());
1774
1775 h_Authorizations.merge(*this, source.embedded());
1776 h_ProxyAuthenticates.merge(*this, source.embedded());
1777 h_WWWAuthenticates.merge(*this, source.embedded());
1778 h_ProxyAuthorizations.merge(*this, source.embedded());
1779
1780 h_AlertInfos.merge(*this, source.embedded());
1781 h_AllowEvents.merge(*this, source.embedded());
1782 h_CallInfos.merge(*this, source.embedded());
1783 h_ErrorInfos.merge(*this, source.embedded());
1784 h_ProxyRequires.merge(*this, source.embedded());
1785 h_Requires.merge(*this, source.embedded());
1786 h_Unsupporteds.merge(*this, source.embedded());
1787 h_AnswerMode.merge(*this, source.embedded());
1788 h_PrivAnswerMode.merge(*this, source.embedded());
1789
1790 h_RSeq.merge(*this, source.embedded());
1791 h_RAck.merge(*this, source.embedded());
1792 }
1793 //unknown header merge
1794 return *this;
1795}
1796
1797void
1798SipMessage::setSecurityAttributes(std::unique_ptr<SecurityAttributes> sec) noexcept
1799{
1800 mSecurityAttributes = std::move(sec);
1801}
1802
1803const std::list<Data>&
1805{
1806 static const std::list<Data> empty;
1807 return mConnectionInfo ? mConnectionInfo->mTlsPeerNames : empty;
1808}
1809
1810const Data&
1812{
1813 return mConnectionInfo ? mConnectionInfo->mTlsSni : Data::Empty;
1814}
1815
1816const CookieList&
1818{
1819 static const CookieList empty;
1820 return mConnectionInfo ? mConnectionInfo->mWsCookies : empty;
1821}
1822
1823std::shared_ptr<WsCookieContext>
1825{
1826 return mConnectionInfo ? mConnectionInfo->mWsCookieContext : nullptr;
1827}
1828
1829// Gives this message a ConnectionInfo of its own that the caller can change,
1830// so the change doesn't reach other messages sharing the current one
1831static std::shared_ptr<ConnectionInfo>
1832copyConnectionInfo(const std::shared_ptr<const ConnectionInfo>& current)
1833{
1834 return current ? std::make_shared<ConnectionInfo>(*current) : std::make_shared<ConnectionInfo>();
1835}
1836
1837void
1838SipMessage::setTlsPeerNames(const std::list<Data>& tlsPeerNames)
1839{
1840 std::shared_ptr<ConnectionInfo> info = copyConnectionInfo(mConnectionInfo);
1841 info->mTlsPeerNames = tlsPeerNames;
1842 mConnectionInfo = std::move(info);
1843}
1844
1845void
1847{
1848 std::shared_ptr<ConnectionInfo> info = copyConnectionInfo(mConnectionInfo);
1849 info->mWsCookies = wsCookies;
1850 mConnectionInfo = std::move(info);
1851}
1852
1853void
1854SipMessage::setWsCookieContext(std::shared_ptr<WsCookieContext> wsCookieContext)
1855{
1856 std::shared_ptr<ConnectionInfo> info = copyConnectionInfo(mConnectionInfo);
1857 info->mWsCookieContext = std::move(wsCookieContext);
1858 mConnectionInfo = std::move(info);
1859}
1860
1861void
1863 const Tuple& dest,
1864 const Data& sigcompId)
1865{
1867
1868 for (MessageDecorator* decorator : mOutboundDecorators)
1869 {
1870 decorator->decorateMessage(*this, src, dest, sigcompId);
1871 }
1872 mIsDecorated = true;
1873}
1874
1875void
1877{
1879
1880 while (!mOutboundDecorators.empty())
1881 {
1882 delete mOutboundDecorators.back();
1883 mOutboundDecorators.pop_back();
1884 }
1885}
1886
1887void
1889{
1890 if (mIsDecorated)
1891 {
1892 for (std::vector<MessageDecorator*>::reverse_iterator r = mOutboundDecorators.rbegin();
1893 r != mOutboundDecorators.rend(); ++r)
1894 {
1895 (*r)->rollbackMessage(*this);
1896 }
1897 mIsDecorated = false;
1898 }
1899}
1900
1901void
1903{
1904 for (MessageDecorator* decorator : mOutboundDecorators)
1905 {
1906 if (decorator->copyToStackCancels())
1907 {
1908 cancel.addOutboundDecorator(std::unique_ptr<MessageDecorator>(decorator->clone()));
1909 }
1910 }
1911}
1912
1913void
1915{
1916 for (MessageDecorator* decorator : mOutboundDecorators)
1917 {
1918 if (decorator->copyToStackFailureAcks())
1919 {
1920 ack.addOutboundDecorator(std::unique_ptr<MessageDecorator>(decorator->clone()));
1921 }
1922 }
1923}
1924
1925/* ====================================================================
1926 * The Vovida Software License, Version 1.0
1927 *
1928 * Copyright (c) 2026 SIP Spectrum, Inc. https://www.sipspectrum.com
1929 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1930 *
1931 * Redistribution and use in source and binary forms, with or without
1932 * modification, are permitted provided that the following conditions
1933 * are met:
1934 *
1935 * 1. Redistributions of source code must retain the above copyright
1936 * notice, this list of conditions and the following disclaimer.
1937 *
1938 * 2. Redistributions in binary form must reproduce the above copyright
1939 * notice, this list of conditions and the following disclaimer in
1940 * the documentation and/or other materials provided with the
1941 * distribution.
1942 *
1943 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1944 * and "Vovida Open Communication Application Library (VOCAL)" must
1945 * not be used to endorse or promote products derived from this
1946 * software without prior written permission. For written
1947 * permission, please contact vocal@vovida.org.
1948 *
1949 * 4. Products derived from this software may not be called "VOCAL", nor
1950 * may "VOCAL" appear in their name, without prior written
1951 * permission of Vovida Networks, Inc.
1952 *
1953 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1954 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1955 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1956 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1957 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1958 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1959 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1960 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1961 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1962 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1963 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1964 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1965 * DAMAGE.
1966 *
1967 * ====================================================================
1968 *
1969 * This software consists of voluntary contributions made by Vovida
1970 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1971 * Inc. For more information on Vovida Networks, Inc., please see
1972 * <http://www.vovida.org/>.
1973 *
1974 * vi: set shiftwidth=3 expandtab:
1975 */
#define defineHeader(_enum, _name, _type, _reference)
Definition Headers.cxx:55
#define defineMultiHeader(_enum, _name, _type, _reference)
Definition Headers.cxx:90
#define DebugLog(args_)
Definition Logger.hxx:128
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define resip_assert(x)
This file needs to work for both C and C++ code.
static const Data ftuEB(" from(tu)")
static const Data tlsdEB(" tlsd=")
static const Data contactEB(" contact=")
static const Data requestEB("SipReq: ")
static const Data tidEB(" tid=")
static std::shared_ptr< ConnectionInfo > copyConnectionInfo(const std::shared_ptr< const ConnectionInfo > &current)
static const Data responseEB("SipResp: ")
static const Data wireEB(" from(wire)")
static const Data cseqEB(" cseq=")
static const Data slashEB(" / ")
static Mimes empty
Represents the "credentials" and "challenge" elements in the SIP grammar.
Definition Auth.hxx:18
The abstract base-class for all exceptions thrown by resip code.
Represents a CSeq header field value (this doesn't have an official name in the RFC 3261 grammar).
Represents the "callid" element in the SIP grammar.
Definition CallId.hxx:18
static HashMap< Mime, ContentsFactoryBase * > & getFactoryMap()
Base class for all SIP body types.
Definition Contents.hxx:51
bool exists(const HeaderBase &headerType) const
checks to see if a header is present
Definition Contents.cxx:189
const H_ContentType::Type & header(const H_ContentType &headerType) const
returns the value of the Content-Type header Throws an Contents::Exception if the header doesn't exis...
Definition Contents.cxx:280
const Mime & getType() const
getter for mime type of message
Definition Contents.hxx:118
virtual Contents * clone() const =0
returns a copy of a Contents object
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
Data & append(const char *str, size_type len)
Appends the specified number of bytes to the end of this Data.
Definition Data.cxx:1058
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
Represents the "SIP-date" element in the RFC 3261 grammar.
Used to accumlate data written to the stream in a DigestBuffer and convert the data to Digest.
Data getHex()
Calls flush() on itself and returns the Digest data in hex format.
size_t getPoolSizeBytes() const
Definition DinkyPool.hxx:54
size_t getPoolBytes() const
Definition DinkyPool.hxx:53
size_t getHeapBytes() const
Definition DinkyPool.hxx:52
static Data encode(const Data &input)
Definition Embedded.cxx:104
Represents the header field value for an Expires-type header.
const Data & getName() const
Represents the "absoluteURI" element in the RFC 3261 grammar.
static HeaderBase * getInstance(Headers::Type typenum)
Definition Headers.hxx:68
virtual Headers::Type getTypeNum() const =0
virtual ParserContainerBase * makeContainer(HeaderFieldValueList *hfvs) const =0
void setParserContainer(ParserContainerBase *parser)
ParserContainerBase * getParserContainer() const
void push_back(const char *buffer, size_t length, bool own)
READ THIS CAREFULLY BEFORE USING THIS FUNCTION.
EncodeStream & encode(EncodeStream &str) const
const char * getBuffer() const
void init(const char *field, size_t length, bool own)
HeaderFieldValue & copyWithPadding(const HeaderFieldValue &rhs)
void toShareData(Data &data) const
static const Data & getHeaderName(int)
Definition Headers.cxx:37
static bool isMulti(Type type)
Definition Headers.cxx:50
Represents an Identity header from RFC8824.
EncodeStream & encode(EncodeStream &str) const
Encodes this element to a stream, in the fashion it should be represented on the wire.
void checkParsed() const
The base-class used for message-passing.
Definition Message.hxx:21
Represents the "media-type" element in the RFC 3261 grammar.
Definition Mime.hxx:20
const Data & subType() const
Definition Mime.cxx:100
const Data & type() const
Definition Mime.cxx:94
void prepareForMessage(SipMessage *msg)
MsgHeaderScanner::ScanChunkResult scanChunk(char *chunk, unsigned int chunkLength, char **unprocessedCharPtr)
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
static const Mime & getStaticType()
BaseException used to indicate parse failures.
Data commutativeParameterHash() const
Abstract Base class implemented in derived class ParserContainer.
virtual void parseAll()=0
pure virtual function to be implemented in derived classes The intention is to provide an ability to ...
Container class for ParserCategory, used by SipMessage to represent multi-valued headers (Contact,...
Represents the "token" element in the RFC 3261 grammar.
Represents the RAck header field value defined in the RFC 3262 grammar.
Represents the "Request-Line" element in the RFC 3261 grammar.
MethodTypes getMethod() const
const Uri & uri() const
virtual EncodeStream & encodeParsed(EncodeStream &str) const
MethodTypes & method()
Base exception for SipMessage related exceptions.
KnownHeaders::const_reference const_reference
void reserve(size_type capacity)
Reserves internal storage for the given number of entries.
iterator insert(Headers::Type type, ValuesFactory &&valuesFactory)
Constructs or reuses a previously erased element for a given header type.
OrderedView ordered() const noexcept
Returns an ordered view over the list of headers.
UsedIterator< TypedHeaders::iterator > iterator
TypedHeaders::const_reference const_reference
iterator find(Headers::Type type) noexcept
Finds header information, if present in the list. Returns end() if not found. Does not produce "unuse...
void clearAndDispose(Disposer &&disposer) noexcept
Clears the container and invokes the dispose function on every element.
TypedHeaders::reference reference
TypedHeaders::size_type size_type
size_type size() const noexcept
Returns the number of elements in the container. Does not consider "unused" elements.
void erase(iterator it) noexcept
Erases an element. Does not free the HeaderFieldValueList object but clears it and marks as "unused".
void clear() noexcept
Clears the container. Does not free HeaderFieldValueList objects but clears them and marks as "unused...
const_iterator end() const noexcept
Represents a SIP message.
void addBuffer(char *buf)
std::unique_ptr< Contents > releaseContents()
Removes the contents from the message.
void copyOutboundDecoratorsToStackFailureAck(SipMessage &ack)
const std::list< Data > & getTlsPeerNames() const
void setRFC2543TransactionId(const Data &tid)
void setContents(const Contents *contents)
Set the contents of the message.
void setStartLine(const char *start, uint32_t len)
static SipMessage * make(const Data &buffer, bool isExternal=false)
Construct a SipMessage object from a string containing a SIP request or response.
bool isRequest() const
Returns true if message is a request, false otherwise.
const Data & getRFC2543TransactionId() const
Calculates an MD5 hash over the Request-URI, To tag (for non-INVITE transactions),...
void setWsCookies(const CookieList &wsCookies)
bool hasForceTarget() const
SipMessage & mergeUri(const Uri &source)
virtual bool isClientTransaction() const
Check if SipMessage is a client transaction.
void setWsCookieContext(std::shared_ptr< WsCookieContext > wsCookieContext)
const Data & methodStr() const
Returns a string containing the SIP method for the message.
Contents * getContents() const
Retrieves the body of a SIP message.
void setBody(const char *start, uint32_t len)
void callOutboundDecorators(const Tuple &src, const Tuple &dest, const Data &sigcompId)
void setRawHeader(const HeaderFieldValueList *hfvs, Headers::Type headerType)
const Data & getTlsSni() const
SNI (TLS server_name) the peer sent in its ClientHello.
void freeMem(bool leaveResponseStuff=false)
void addOutboundDecorator(std::unique_ptr< MessageDecorator > md)
Call a MessageDecorator to process the message before it is sent to the transport.
void setSecurityAttributes(std::unique_ptr< SecurityAttributes >) noexcept
void init(const SipMessage &rhs)
void setForceTarget(const Uri &uri)
deal with a notion of an "out-of-band" forced target for SIP routing
bool empty(const HeaderBase &headerType) const
Returns true if the header field is present and non-empty, false otherwise.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
virtual const Data & getTransactionId() const
Returns the transaction id from the branch or if 2543, the computed hash.
void addHeader(Headers::Type header, const char *headerName, uint32_t headerNameLen, const char *value, uint32_t valuelen)
Add HeaderFieldValue given enum, header name and value.
EncodeStream & encodeEmbedded(EncodeStream &str) const
bool isResponse() const
Returns true if message is a response, false otherwise.
const RequestLine & const_header(const RequestLineType &l) const
void setRawBody(const HeaderFieldValue &body)
Remove any existing body/contents, and (if non-empty) set the body to {body}.
const Uri & getForceTarget() const
SipMessage(const Tuple *receivedTransport=0)
EncodeStream & encodeSingleHeader(Headers::Type type, EncodeStream &str) const
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
virtual EncodeStream & encodeSipFrag(EncodeStream &str) const
static bool checkContentLength
void remove(const HeaderBase &headerType)
Prevents a header field from being present when the message is prepared for sending to a transport.
virtual Message * clone() const
virtual EncodeStream & encodeBrief(EncodeStream &str) const
output a brief description to stream
void copyOutboundDecoratorsToStackCancel(SipMessage &cancel)
void rollbackOutboundDecorators()
virtual ~SipMessage()
void clear(bool leaveResponseStuff=false)
const CookieList & getWsCookies() const
bool isExternal() const
Check if SipMessage is to be treated as it came off the wire.
void clearOutboundDecorators()
std::shared_ptr< WsCookieContext > getWsCookieContext() const noexcept
SipMessage & operator=(const SipMessage &rhs)
void setTlsPeerNames(const std::list< Data > &tlsPeerNames)
const HeaderFieldValueList * getRawHeader(Headers::Type headerType) const
typeless header interface
resip::MethodTypes method() const
returns the method type of the message
Data getCanonicalIdentityString() const
virtual EncodeStream & encode(EncodeStream &str) const
Generate a string from the SipMessage object.
virtual StartLine * clone() const =0
virtual ~StartLine()
Definition StartLine.hxx:18
Represents the "Status-Line" element in the RFC 3261 grammar.
A dirt-simple lightweight stl pool allocator meant for use in short-lifetime objects.
Represents the "header-value" element in the RFC 3261 grammar (ie, an unknown header field value).
static const char * SPACE
Definition Symbols.hxx:34
static const char * QUESTION
Definition Symbols.hxx:42
static const char * BAR
Definition Symbols.hxx:16
static const char * AMPERSAND
Definition Symbols.hxx:43
static const char * STAR
Definition Symbols.hxx:45
static const char * CRLF
Definition Symbols.hxx:21
This class is used to get the current system time.
Definition Timer.hxx:31
Generically represents a token whose value can be wrapped and encoded using double quotes.
Represents the "token" element in the RFC 3261 grammar.
Definition Token.hxx:18
Represents a network address.
Definition Tuple.hxx:59
void setType(TransportType type)
Definition Tuple.hxx:123
Represents a numeric-with-comment header field value.
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
Data getAor() const
Definition Uri.cxx:1095
Data & password()
Definition Uri.hxx:147
SipMessage & embedded()
Definition Uri.cxx:1586
int & port()
Definition Uri.hxx:145
Data & scheme()
Definition Uri.hxx:143
void removeEmbedded()
Definition Uri.cxx:350
bool hasEmbedded() const
Definition Uri.cxx:343
bool exists(const Param< Uri > &paramType) const
Definition Uri.cxx:1701
Data & user()
Definition Uri.hxx:42
void remove(const Param< Uri > &paramType)
Definition Uri.cxx:1709
Data & host()
Definition Uri.hxx:40
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
Represents the "via-parm" element in the RFC 3261 grammar.
Definition Via.hxx:18
Represents the "warning-value" element in the RFC 3261 grammar.
An ostream that operates on an existing Data.
This file is used to handle compatibility fixes/tweaks so reSIProcate can function on multiple platfo...
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
Definition Headers.cxx:348
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
unsigned int uint32_t
Definition Stun.hxx:34
const Data & getMethodName(MethodTypes t)
RequestLineType h_RequestLine
Definition Headers.cxx:347
ParserContainer< StringCategory > StringCategories
Definition Headers.hxx:213
MethodTypes getMethodType(const Data &name)
std::vector< Cookie > CookieList
Definition Cookie.hxx:35
H_AllowEventss h_AllowEvents
Definition Headers.cxx:143
H_CallId h_CallId
Definition Headers.cxx:266
#define EncodeStream