reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ConnectionBase.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
5#include <memory>
6
7#include "rutil/Logger.hxx"
18#include "rutil/Sha1.hxx"
19
20#ifdef USE_SSL
23#endif
24
26
27#ifdef USE_SIGCOMP
28#include <osc/Stack.h>
29#include <osc/TcpStream.h>
30#include <osc/SigcompMessage.h>
31#include <osc/StateChanges.h>
32#endif
33
34using namespace resip;
35
36#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
37
38char
39ConnectionBase::connectionStates[ConnectionBase::MAX][32] = { "NewMessage", "ReadingHeaders", "PartialBody" };
40
41#ifndef RESIP_SIP_MSG_MAX_BYTES
42#define RESIP_SIP_MSG_MAX_BYTES 10485760
43#endif
44
45size_t
46ConnectionBase::messageSizeMax = RESIP_SIP_MSG_MAX_BYTES;
47
48ConnectionBase::ConnectionBase(Transport* transport, const Tuple& who, Compression &compression)
49 : mSendPos(0),
50 mTransport(transport),
51 mWho(who),
52 mFailureReason(TransportFailure::None),
53 mFailureSubCode(0),
54 mCompression(compression),
55// NO: #ifdef USE_SIGCOMP // class def doesn't decl members conditionally
56 mSigcompStack(0),
57 mSigcompFramer(0),
58// NO: #endif
59 mSendingTransmissionFormat(Unknown),
60 mReceivingTransmissionFormat(Unknown),
61 mMessage(0),
62 mBuffer(0),
63 mBufferPos(0),
64 mBufferSize(0),
65 mWsFrameExtractor((Data::size_type)messageSizeMax),
66 mLastUsed(Timer::getTimeMs()),
67 mConnState(NewMessage)
68{
69 DebugLog (<< "ConnectionBase::ConnectionBase, who: " << mWho << " " << this);
70#ifdef USE_SIGCOMP
72 {
73 DebugLog (<< "Compression enabled for connection, who: " << mWho << " " << this);
74 mSigcompStack = new osc::Stack(mCompression.getStateHandler());
76 }
77 else
78 {
79 DebugLog (<< "Compression disabled for connection, who: " << mWho << " " << this);
80 }
81#else
82 DebugLog (<< "No compression library available, who: " << mWho << " " << this);
83#endif
84
85 if(mTransport)
86 {
88 }
89}
90
92{
93 if(mTransport)
94 {
96 }
97
98 while (!mOutstandingSends.empty())
99 {
100 SendData* sendData = mOutstandingSends.front();
101 if (mTransport)
102 {
103 mTransport->fail(sendData->transactionId,
106 }
107 delete sendData;
108 mOutstandingSends.pop_front();
109 }
110 delete [] mBuffer;
111 delete mMessage;
112#ifdef USE_SIGCOMP
113 delete mSigcompStack;
114#endif
115
116 DebugLog (<< "ConnectionBase::~ConnectionBase, who: " << mWho << " " << this);
117}
118
119void
120ConnectionBase::setFailureReason(TransportFailure::FailureReason failReason, int subCode, const Data& failureString)
121{
122 if (failReason > mFailureReason)
123 {
124 mFailureReason = failReason;
125 mFailureSubCode = subCode;
126 mFailureString = failureString;
127 }
128}
129
130void
132{
133 mAdditionalFailureStrings.push_back(additionalFailureString);
134}
135
138{
139 return mWho.mFlowKey;
140}
141
142bool
144{
145 DebugLog(<< "In State: " << connectionStates[mConnState] << ", who: " << mWho << " " << this);
146
147 start: // If there is an overhang come back here, effectively recursing
148
149 switch(mConnState)
150 {
151 case NewMessage:
152 {
153 if (bytesRead >= 4 && strncmp(mBuffer + mBufferPos, Symbols::CRLFCRLF, 4) == 0)
154 {
155 DebugLog(<< "Got incoming double-CRLF keepalive (aka ping), who: " << mWho << " " << this);
156 mBufferPos += 4;
157 bytesRead -= 4;
158 onDoubleCRLF();
159 if (bytesRead)
160 {
161 goto start;
162 }
163 else
164 {
165 delete [] mBuffer;
166 mBuffer = 0;
167 return true;
168 }
169 }
170 else if (bytesRead >= 2 && strncmp(mBuffer + mBufferPos, Symbols::CRLF, 2) == 0)
171 {
172 //DebugLog(<< "Got incoming CRLF keepalive response (aka pong), who: " << mWho << " " << this);
173 mBufferPos += 2;
174 bytesRead -= 2;
175 onSingleCRLF();
176 if (bytesRead)
177 {
178 goto start;
179 }
180 else
181 {
182 delete [] mBuffer;
183 mBuffer = 0;
184 return true;
185 }
186 }
187
189 mMessage = new SipMessage(&mTransport->getTuple());
190
191 DebugLog(<< "ConnectionBase::process setting source, who: " << mWho << " " << this);
192 mMessage->setSource(mWho);
193 mMessage->setTlsDomain(mTransport->tlsDomain());
194 mMessage->setConnectionInfo(getConnectionInfo());
195 mMsgHeaderScanner.prepareForMessage(mMessage);
196 // Fall through to the next case.
197 }
198 case ReadingHeaders:
199 {
200 unsigned int chunkLength = (unsigned int)mBufferPos + bytesRead;
201 char *unprocessedCharPtr;
202 MsgHeaderScanner::ScanChunkResult scanChunkResult =
203 mMsgHeaderScanner.scanChunk(mBuffer,
204 chunkLength,
205 &unprocessedCharPtr);
206 if (scanChunkResult == MsgHeaderScanner::scrError)
207 {
208 //.jacob. Not a terribly informative warning.
209 WarningLog(<< "Discarding preparse, who: " << mWho << " " << this);
210 delete [] mBuffer;
211 mBuffer = 0;
212 delete mMessage;
213 mMessage = 0;
214 mConnState = NewMessage;
215 return false;
216 }
217
218 if (mMsgHeaderScanner.getHeaderCount() > 1024)
219 {
220 WarningLog(<< "Discarding preparse; too many headers, who: " << mWho << " " << this);
221 delete [] mBuffer;
222 mBuffer = 0;
223 delete mMessage;
224 mMessage = 0;
225 mConnState = NewMessage;
226 return false;
227 }
228
229 unsigned int numUnprocessedChars =
230 (unsigned int)((mBuffer + chunkLength) - unprocessedCharPtr);
231
232 if(numUnprocessedChars > ConnectionBase::ChunkSize &&
233 scanChunkResult == MsgHeaderScanner::scrNextChunk)
234 {
235 WarningLog(<< "Discarding preparse; header-field-value (or "
236 "header name) too long, who: " << mWho << " " << this);
237 delete [] mBuffer;
238 mBuffer = 0;
239 delete mMessage;
240 mMessage = 0;
241 mConnState = NewMessage;
242 return false;
243 }
244
245 if(numUnprocessedChars==chunkLength)
246 {
247 // .bwc. MsgHeaderScanner wasn't able to parse anything useful;
248 // don't bother mMessage yet, but make more room in mBuffer.
249 size_t size = numUnprocessedChars*3/2;
250 if (size < ConnectionBase::ChunkSize)
251 {
253 }
254 char* newBuffer = 0;
255 try
256 {
257 newBuffer=MsgHeaderScanner::allocateBuffer(size);
258 }
259 catch(std::bad_alloc&)
260 {
261 ErrLog(<<"Failed to alloc a buffer during preparse, who: " << mWho << " " << this);
262 return false;
263 }
264 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars);
265 delete [] mBuffer;
266 mBuffer = newBuffer;
267 mBufferPos = numUnprocessedChars;
268 mBufferSize = size;
269 mConnState = ReadingHeaders;
270 return true;
271 }
272
273 mMessage->addBuffer(mBuffer);
274 mBuffer=0;
275
276 if (scanChunkResult == MsgHeaderScanner::scrNextChunk)
277 {
278 // Message header is incomplete...
279 if (numUnprocessedChars == 0)
280 {
281 // ...but the chunk is completely processed.
282 //.jacob. I've discarded the "assigned" concept.
283 //DebugLog(<< "Data assigned, not fragmented, not complete");
284 try
285 {
287 }
288 catch(std::bad_alloc&)
289 {
290 ErrLog(<<"Failed to alloc a buffer during preparse, who: " << mWho << " " << this);
291 return false;
292 }
293 mBufferPos = 0;
294 mBufferSize = ChunkSize;
295 }
296 else
297 {
298 // ...but some of the chunk must be shifted into the next one.
299 size_t size = numUnprocessedChars*3/2;
300 if (size < ConnectionBase::ChunkSize)
301 {
303 }
304 char* newBuffer = 0;
305 try
306 {
307 newBuffer = MsgHeaderScanner::allocateBuffer(size);
308 }
309 catch(std::bad_alloc&)
310 {
311 ErrLog(<<"Failed to alloc a buffer during preparse, who: " << mWho << " " << this);
312 return false;
313 }
314 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars);
315 mBuffer = newBuffer;
316 mBufferPos = numUnprocessedChars;
317 mBufferSize = size;
318 }
319 mConnState = ReadingHeaders;
320 }
321 else
322 {
323 size_t contentLength = 0;
324
325 try
326 {
327 // The message header is complete.
328 contentLength=mMessage->const_header(h_ContentLength).value();
329 }
330 catch(resip::BaseException& e) // Could be SipMessage::Exception or ParseException
331 {
332 WarningLog(<<"Malformed Content-Length in connection-based transport"
333 ". Not much we can do to fix this, who: " << mWho << " " << this << ": " << e);
334 // .bwc. Bad Content-Length. We are hosed.
335 delete mMessage;
336 mMessage = 0;
337 mBuffer = 0;
338 // .bwc. mMessage just took ownership of mBuffer, so we don't
339 // delete it here. We do zero it though, for completeness.
340 //.jacob. Shouldn't the state also be set here?
341 return false;
342 }
343
344 if(contentLength > messageSizeMax || contentLength < 0)
345 {
346 WarningLog(<<"Content-Length in connection-based "
347 "transport exceeds maximum " << messageSizeMax << ", who: " << mWho << " " << this);
348 delete mMessage;
349 mMessage = 0;
350 mBuffer = 0;
351 // .bwc. mMessage just took ownership of mBuffer, so we don't
352 // delete it here. We do zero it though, for completeness.
353 //.jacob. Shouldn't the state also be set here?
354 return false;
355 }
356
357 if (numUnprocessedChars < contentLength)
358 {
359 // The message body is incomplete.
360 DebugLog(<< "partial body received, who: " << mWho << " " << this);
361 size_t newSize=resipMin(resipMax((size_t)numUnprocessedChars*3/2,
363 contentLength);
364 char* newBuffer = MsgHeaderScanner::allocateBuffer(newSize);
365 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars);
366 mBufferPos = numUnprocessedChars;
367 mBufferSize = newSize;
368 mBuffer = newBuffer;
369
370 mConnState = PartialBody;
371 }
372 else
373 {
374 // Do this stuff BEFORE we kick the message out the door.
375 // Remember, deleting or passing mMessage on invalidates our
376 // buffer!
377 int overHang = numUnprocessedChars - (int)contentLength;
378
379 mConnState = NewMessage;
380 mBuffer = 0;
381 if (overHang > 0)
382 {
383 // The next message has been partially read.
384 size_t size = overHang*3/2;
385 if (size < ConnectionBase::ChunkSize)
386 {
388 }
389 char* newBuffer = MsgHeaderScanner::allocateBuffer(size);
390 memcpy(newBuffer,
391 unprocessedCharPtr + contentLength,
392 overHang);
393 mBuffer = newBuffer;
394 mBufferPos = 0;
395 mBufferSize = size;
396
397 DebugLog (<< "Extra bytes after message: " << overHang << ", who: " << mWho << " " << this);
398 //DebugLog (<< Data(mBuffer, overHang));
399
400 bytesRead = overHang;
401 }
402
403 // The message body is complete.
404 if (contentLength > 0)
405 mMessage->setBody(unprocessedCharPtr, (uint32_t)contentLength);
409 && mMessage->isRequest()))
410 {
411 const uint32_t expectedWait(mTransport->getExpectedWaitForIncoming());
412 // .bwc. If this fifo is REJECTING_NEW_WORK, we will drop
413 // requests but not responses ( ?bwc? is this right for ACK?).
414 // If we are REJECTING_NON_ESSENTIAL,
415 // we reject all incoming work, since losing something from the
416 // wire will not cause instability or leaks (see
417 // CongestionManager.hxx)
418
419 // .bwc. This handles all appropriate checking for whether
420 // this is a response or an ACK.
421 std::unique_ptr<SendData> tryLater(transport()->make503(*mMessage, expectedWait));
422 if(tryLater.get())
423 {
424 transport()->send(std::move(tryLater));
425 }
426 delete mMessage; // dropping message due to congestion
427 mMessage = 0;
428 }
429 else if (!transport()->basicCheck(*mMessage))
430 {
431 delete mMessage;
432 mMessage = 0;
433 }
434 else
435 {
436 Transport::stampReceived(mMessage);
437 DebugLog(<< "##Connection, who: " << mWho << " " << this << " received: " << *mMessage);
439 mTransport->pushRxMsgUp(mMessage);
440 mMessage = 0;
441 }
442
443 if (overHang > 0)
444 {
445 goto start;
446 }
447 }
448 }
449 break;
450 }
451 case PartialBody:
452 {
453 size_t contentLength = 0;
454
455 try
456 {
457 contentLength = mMessage->const_header(h_ContentLength).value();
458 }
459 catch(resip::BaseException& e) // Could be SipMessage::Exception or ParseException
460 {
461 WarningLog(<<"Malformed Content-Length in connection-based transport"
462 ". Not much we can do to fix this, who: " << mWho << " " << this << ": " << e);
463 // .bwc. Bad Content-Length. We are hosed.
464 delete [] mBuffer;
465 mBuffer = 0;
466 delete mMessage;
467 mMessage = 0;
468 //.jacob. Shouldn't the state also be set here?
469 return false;
470 }
471
472 mBufferPos += bytesRead;
473 if (mBufferPos >= contentLength)
474 {
475 size_t overHang = mBufferPos - contentLength;
476 char *overHangStart = mBuffer + contentLength;
477
478 mMessage->addBuffer(mBuffer);
479 mMessage->setBody(mBuffer, (uint32_t)contentLength);
480 mConnState = NewMessage;
481 mBuffer = 0;
482
483 if (overHang > 0)
484 {
485 // The next message has been partially read.
486 size_t size = overHang * 3 / 2;
487 if (size < ConnectionBase::ChunkSize)
488 {
490 }
491 char* newBuffer = MsgHeaderScanner::allocateBuffer(size);
492 memcpy(newBuffer, overHangStart, overHang);
493 mBuffer = newBuffer;
494 mBufferPos = 0;
495 mBufferSize = size;
496
497 DebugLog(<< "Extra bytes after message: " << overHang << ", who: " << mWho << " " << this);
498 //DebugLog(<< Data(mBuffer, overHang));
499
500 bytesRead = (int)overHang;
501 }
502
503 // .bwc. basicCheck takes up substantial CPU. Don't bother doing it
504 // if we're overloaded.
508 && mMessage->isRequest()))
509 {
510 const uint32_t expectedWait(mTransport->getExpectedWaitForIncoming());
511 // .bwc. If this fifo is REJECTING_NEW_WORK, we will drop
512 // requests but not responses ( ?bwc? is this right for ACK?).
513 // If we are REJECTING_NON_ESSENTIAL,
514 // we reject all incoming work, since losing something from the
515 // wire will not cause instability or leaks (see
516 // CongestionManager.hxx)
517
518 // .bwc. This handles all appropriate checking for whether
519 // this is a response or an ACK.
520 std::unique_ptr<SendData> tryLater = transport()->make503(*mMessage, expectedWait);
521 if(tryLater.get())
522 {
523 transport()->send(std::move(tryLater));
524 }
525 delete mMessage; // dropping message due to congestion
526 mMessage = 0;
527 }
528 else if (!transport()->basicCheck(*mMessage))
529 {
530 delete mMessage;
531 mMessage = 0;
532 }
533 else
534 {
535 DebugLog(<< "##ConnectionBase, who: " << mWho << " " << this << " received: " << *mMessage);
536
537 Transport::stampReceived(mMessage);
539 mTransport->pushRxMsgUp(mMessage);
540 mMessage = 0;
541 }
542
543 if (overHang > 0)
544 {
545 goto start;
546 }
547 }
548 else if (mBufferPos == mBufferSize)
549 {
550 // .bwc. We've filled our buffer and haven't read contentLength bytes yet; go ahead and make more room.
551 resip_assert(contentLength >= mBufferSize);
552 size_t newSize = resipMin(mBufferSize*3/2, contentLength);
553 char* newBuffer = 0;
554 try
555 {
556 newBuffer=new char[newSize];
557 }
558 catch(std::bad_alloc&)
559 {
560 ErrLog(<<"Failed to alloc a buffer while receiving body, who: " << mWho << " " << this);
561 return false;
562 }
563 memcpy(newBuffer, mBuffer, mBufferSize);
564 mBufferSize=newSize;
565 delete [] mBuffer;
566 mBuffer = newBuffer;
567 }
568 break;
569 }
570 default:
571 resip_assert(0);
572 }
573 return true;
574}
575
576void
578{
579 Data name;
580 Data value;
581 StringCategories::const_iterator it = message->header(h_Cookies).begin();
582 for (; it != message->header(h_Cookies).end(); ++it)
583 {
584 ParseBuffer pb((*it).value());
585 while(!pb.eof())
586 {
587 const char* anchor = pb.skipWhitespace();
588
590 pb.data(name, anchor);
591
592 anchor = pb.skipChar(Symbols::EQUALS[0]);
593 if(*(pb.position()) == Symbols::DOUBLE_QUOTE[0])
594 {
595 anchor = pb.skipChar(Symbols::DOUBLE_QUOTE[0]);
597 pb.data(value, anchor);
599 }
600 else
601 {
603 pb.data(value, anchor);
604 }
605
606 Cookie cookie(name, value);
607 cookieList.push_back(cookie);
608 DebugLog(<< "Cookie: " << cookie << ", who: " << mWho << " " << this);
609
610 if(!pb.eof() && *(pb.position()) == Symbols::SEMI_COLON[0])
611 {
613 }
614
615 pb.skipWhitespace();
616 }
617 }
618}
619
620/*
621 * Returns true if handshake complete, false if more bytes needed
622 * Sets dropConnection = true if an error occurs
623 */
624bool
625ConnectionBase::wsProcessHandshake(int bytesRead, bool &dropConnection)
626{
627 mConnState = WebSocket;
628 dropConnection = false;
629
630 if(mBufferPos + bytesRead > messageSizeMax)
631 {
632 WarningLog(<<"Too many bytes received during WS handshake, dropping connection. Max message size = " << messageSizeMax << ", who: " << mWho << " " << this);
633 dropConnection = true;
634 return false;
635 }
636
638 mMessage = new SipMessage(&mTransport->getTuple());
639 resip_assert(mMessage);
640
641 mMessage->setSource(mWho);
642 mMessage->setTlsDomain(mTransport->tlsDomain());
643
644 if (!scanMsgHeader(bytesRead))
645 {
646 return false;
647 }
648
649 try
650 {
651 WsConnectionBase* wsConnectionBase = dynamic_cast<WsConnectionBase*>(this);
652 CookieList cookieList;
653 if(wsConnectionBase)
654 {
655 std::shared_ptr<WsCookieContext> wsCookieContext;
656 if (mMessage->exists(h_Cookies))
657 {
658 WsBaseTransport* wst = dynamic_cast<WsBaseTransport*>(mTransport);
659 resip_assert(wst);
660 try
661 {
662 wsParseCookies(cookieList, mMessage);
663 wsConnectionBase->setCookies(cookieList);
664 // Use of resip WsCookieContext capabilities is not mandatory,
665 // only try to use it if cookieContextFactory is available
666 if(wst->cookieContextFactory().get())
667 {
668 Uri& requestUri = mMessage->header(h_RequestLine).uri();
669 wsCookieContext = wst->cookieContextFactory()->makeCookieContext(cookieList, requestUri);
670 wsConnectionBase->setWsCookieContext(wsCookieContext);
671 }
672 }
673 catch(ParseException& ex)
674 {
675 WarningLog(<<"Failed to parse cookies into WsCookieContext, who: " << mWho << " " << this << ": " << ex);
676 }
677 }
678 std::shared_ptr<WsConnectionValidator> wsConnectionValidator = wsConnectionBase->connectionValidator();
679 if(wsConnectionValidator &&
680 (!wsCookieContext || !wsConnectionValidator->validateConnection(*wsCookieContext)))
681 {
682 ErrLog(<<"WebSocket cookie validation failed, dropping connection, who: " << mWho << " " << this);
683 // FIXME: should send back a HTTP error code:
684 // 400 if the cookie was not in the right syntax
685 // 403 if the cookie was well formed but rejected
686 // due to expiry or a bad HMAC
687 delete mMessage;
688 mMessage = 0;
689 mBufferPos = 0;
690 dropConnection = true;
691 return false;
692 }
693 }
694
695 std::unique_ptr<Data> wsResponsePtr = makeWsHandshakeResponse();
696
697 if (wsResponsePtr.get())
698 {
699 DebugLog (<< "WebSocket upgrade accepted, cookie count = " << cookieList.size() << ", who: " << mWho << " " << this);
700
701 mOutstandingSends.push_back(new SendData(
702 who(),
703 *wsResponsePtr.get(),
706 true));
707 }
708 else
709 {
710 ErrLog(<<"Failed to parse WebSocket initialization request, who: " << mWho << " " << this);
711 delete mMessage;
712 mMessage = 0;
713 mBufferPos = 0;
714 dropConnection = true;
715 return false;
716 }
717 }
718 catch(resip::ParseException& e)
719 {
720 ErrLog(<<"Cannot auth request is missing, who: " << mWho << " " << this << ": " << e);
721 delete mMessage;
722 mMessage = 0;
723 mBufferPos = 0;
724 dropConnection = true;
725 return false;
726 }
727
728 delete mMessage;
729 mMessage=0;
730 mBufferPos = 0;
731
732 return true;
733}
734
735bool
736ConnectionBase::scanMsgHeader(int bytesRead)
737{
738 mMsgHeaderScanner.prepareForMessage(mMessage);
739 char *unprocessedCharPtr;
740 MsgHeaderScanner::ScanChunkResult scanResult = mMsgHeaderScanner.scanChunk(mBuffer, (int)mBufferPos + bytesRead, &unprocessedCharPtr);
741 if (scanResult != MsgHeaderScanner::scrEnd)
742 {
743 if(scanResult != MsgHeaderScanner::scrNextChunk)
744 {
745 StackLog(<<"Failed to parse message, more bytes needed, who: " << mWho << " " << this);
746 StackLog(<< Data(mBuffer, bytesRead));
747 }
748 delete mMessage;
749 mMessage=0;
750 mBufferPos += bytesRead;
751 return false;
752 }
753 return true;
754}
755
756std::unique_ptr<Data>
757ConnectionBase::makeWsHandshakeResponse()
758{
759 std::unique_ptr<Data> responsePtr;
760 if(isUsingSecWebSocketKey())
761 {
762 responsePtr.reset(new Data("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
763 "Upgrade: WebSocket\r\n"
764 "Connection: Upgrade\r\n"
765 "Sec-WebSocket-Protocol: sip\r\n"));
766
767 DigestStream wsSha1Stream(SHA1);
768 wsSha1Stream << (mMessage->const_header(h_SecWebSocketKey).value() + Symbols::WebsocketMagicGUID);
769 Data wsAcceptKey = wsSha1Stream.getBin().base64encode();
770 *responsePtr += "Sec-WebSocket-Accept: " + wsAcceptKey + "\r\n\r\n";
771 }
772 else if(isUsingDeprecatedSecWebSocketKeys())
773 {
774 ErrLog(<<"WS client wants to use depracated protocol version, unsupported, who: " << mWho << " " << this);
775 }
776 else
777 {
778 ErrLog(<<"No SecWebSocketKey header, who: " << mWho << " " << this);
779 }
780 return responsePtr;
781}
782
783bool ConnectionBase::isUsingDeprecatedSecWebSocketKeys()
784{
785 resip_assert(mMessage);
786 return mMessage->exists(h_SecWebSocketKey1) &&
787 mMessage->exists(h_SecWebSocketKey2);
788}
789
790bool ConnectionBase::isUsingSecWebSocketKey()
791{
792 resip_assert(mMessage);
793 return mMessage->exists(h_SecWebSocketKey);
794}
795
796bool
798{
799 bool dropConnection = false;
800 // Always consumes the whole buffer:
801 std::unique_ptr<Data> msg = mWsFrameExtractor.processBytes((uint8_t*)mBuffer, bytesRead, dropConnection);
802
803 while(msg.get())
804 {
805 // mWsBuffer should now contain a discrete SIP message, let the
806 // stack go to work on it
807
808 if(msg->size() == 4 && memcmp(msg->data(), "\r\n\r\n", 4) == 0)
809 {
810 // sending a keep alive reply now
811 StackLog(<<"got a SIP ping embedded in WebSocket frame, replying, who: " << mWho << " " << this);
812 onDoubleCRLF();
813 msg = mWsFrameExtractor.processBytes(0, 0, dropConnection);
814 continue;
815 }
816
818 mMessage = new SipMessage(&mTransport->getTuple());
819
820 mMessage->setSource(mWho);
821 mMessage->setTlsDomain(mTransport->tlsDomain());
822 mMessage->setConnectionInfo(getConnectionInfo());
823
824 Data::size_type msg_len = msg->size();
825 // cast permitted, as it is borrowed:
826 char *sipBuffer = (char *)msg->data();
827 mMessage->addBuffer(sipBuffer);
828 mMsgHeaderScanner.prepareForMessage(mMessage);
829 char *unprocessedCharPtr;
830 if (mMsgHeaderScanner.scanChunk(sipBuffer,
831 (unsigned int)msg_len,
832 &unprocessedCharPtr) !=
834 {
835 StackLog(<<"Scanner rejecting WebSocket SIP message as unparsable, length=" << msg_len << ", who: " << mWho << " " << this);
836 StackLog(<< Data(sipBuffer, msg_len));
837 delete mMessage;
838 mMessage=0;
839 }
840
841 unsigned int used = (unsigned int)(unprocessedCharPtr - sipBuffer);
842 if (mMessage && (used < msg_len))
843 {
844 mMessage->setBody(sipBuffer+used, (uint32_t)msg_len-used);
845 }
846
847 if (mMessage && !transport()->basicCheck(*mMessage))
848 {
849 delete mMessage;
850 mMessage = 0;
851 }
852
853 if (mMessage)
854 {
855 Transport::stampReceived(mMessage);
857 mTransport->pushRxMsgUp(mMessage);
858 mMessage = 0;
859 }
860 else
861 {
862 // Something wrong...
863 ErrLog(<< "We don't have a valid SIP message, maybe drop the connection? who: " << mWho << " " << this);
864 }
865 msg = mWsFrameExtractor.processBytes(0, 0, dropConnection);
866 }
867
868 // Close, Ping and Pong frames are not SIP, so they are not passed to the parser
869 // above (a browser closing its WebSocket used to be logged there as an invalid
870 // SIP message)
872 while(mWsFrameExtractor.popControlFrame(control))
873 {
874 switch(control.opcode)
875 {
877 {
878 Data status("none");
879 if(control.payload.size() >= 2)
880 {
881 const unsigned char* code = (const unsigned char*)control.payload.data();
882 status = Data((code[0] << 8) | code[1]);
883 }
884 InfoLog(<< "WebSocket closed by the peer, status " << status << ", closing connection, who: " << mWho << " " << this);
885 onWsClose(control.payload);
886 break;
887 }
889 StackLog(<< "got a WebSocket Ping, replying, who: " << mWho << " " << this);
890 onWsPing(control.payload);
891 break;
892 default:
893 StackLog(<< "got a WebSocket Pong, who: " << mWho << " " << this);
894 break;
895 }
896 }
897
898 if(dropConnection)
899 {
900 return false;
901 }
902
903 return true;
904}
905
906#ifdef USE_SIGCOMP
907void
909{
910 mConnState = SigComp;
911
912 if (!mSigcompFramer)
913 {
914 mSigcompFramer = new osc::TcpStream();
915 }
916
917 mSigcompFramer->addData(mBuffer, bytesRead);
918 size_t bytesUncompressed;
919 osc::StateChanges *sc = 0;
920 char *uncompressed = new char[65536];
921 while ((bytesUncompressed = mSigcompStack->uncompressMessage(
922 *mSigcompFramer, uncompressed, 65536, sc)) > 0)
923 {
924 DebugLog (<< "Uncompressed Connection-oriented message, who: " << mWho << " " << this);
925 mMessage = new SipMessage(&mTransport->getTuple());
926
927 mMessage->setSource(mWho);
928 mMessage->setTlsDomain(mTransport->tlsDomain());
929 mMessage->setConnectionInfo(getConnectionInfo());
930
931 char *sipBuffer = MsgHeaderScanner::allocateBuffer(bytesUncompressed);
932 memmove(sipBuffer, uncompressed, bytesUncompressed);
933 mMessage->addBuffer(sipBuffer);
934 mMsgHeaderScanner.prepareForMessage(mMessage);
935 char *unprocessedCharPtr;
936 if (mMsgHeaderScanner.scanChunk(sipBuffer,
937 bytesUncompressed,
938 &unprocessedCharPtr) !=
940 {
941 StackLog(<<"Scanner rejecting compressed message as unparsable, who: " << mWho << " " << this);
942 StackLog(<< Data(sipBuffer, bytesUncompressed));
943 delete mMessage;
944 mMessage=0;
945 }
946
947 unsigned int used = unprocessedCharPtr - sipBuffer;
948 if (mMessage && (used < bytesUncompressed))
949 {
950 mMessage->setBody(sipBuffer+used, bytesUncompressed-used);
951 }
952
953 if (mMessage && !transport()->basicCheck(*mMessage))
954 {
955 delete mMessage;
956 mMessage = 0;
957 }
958
959 if (mMessage)
960 {
961 Transport::stampReceived(mMessage);
962 // If the message made it this far, we should let it store
963 // SigComp state: extract the compartment ID.
964 const Via &via = mMessage->const_header(h_Vias).front();
965 if (mMessage->isRequest())
966 {
967 // For requests, the compartment ID is read out of the
968 // top via header field; if not present, we use the
969 // TCP connection for identification purposes.
970 if (via.exists(p_sigcompId))
971 {
972 Data compId = via.param(p_sigcompId);
973 if(!compId.empty())
974 {
975 mSigcompStack->provideCompartmentId(sc, compId.data(), compId.size());
976 }
977 }
978 else
979 {
980 mSigcompStack->provideCompartmentId(sc, this, sizeof(this));
981 }
982 }
983 else
984 {
985 // For responses, the compartment ID is supposed to be
986 // the same as the compartment ID of the request. We
987 // *could* dig down into the transaction layer to try to
988 // figure this out, but that's a royal pain, and a rather
989 // severe layer violation. In practice, we're going to ferret
990 // the ID out of the the Via header field, which is where we
991 // squirreled it away when we sent this request in the first place.
992 Data compId = via.param(p_branch).getSigcompCompartment();
993 if(!compId.empty())
994 {
995 mSigcompStack->provideCompartmentId(sc, compId.data(), compId.size());
996 }
997 }
999 mTransport->pushRxMsgUp(mMessage);
1000 mMessage = 0;
1001 sc = 0;
1002 }
1003 else
1004 {
1005 delete sc;
1006 sc = 0;
1007 }
1008 }
1009 delete [] uncompressed;
1010
1011 // If there was a decompression failure, let the other side know.
1012 osc::SigcompMessage *nack = mSigcompStack->getNack();
1013 if (nack)
1014 {
1016 {
1017 // !bwc! We are not telling anyone that we're interested in having our
1018 // FD put in the writable set...
1019 mOutstandingSends.push_back(new SendData(
1020 who(),
1021 Data(nack->getStreamMessage(), nack->getStreamLength()),
1024 true));
1025 }
1026 else
1027 {
1028 delete nack;
1029 }
1030 }
1031}
1032#endif
1033
1034std::pair<char*, size_t>
1036{
1037 if (mConnState == NewMessage)
1038 {
1039 if (!mBuffer)
1040 {
1041 DebugLog (<< "Creating buffer for, who: " << mWho << " " << this);
1042
1044 mBufferSize = ConnectionBase::ChunkSize;
1045 }
1046 mBufferPos = 0;
1047 }
1048 return getCurrentWriteBuffer();
1049}
1050
1051std::pair<char*, size_t>
1053{
1054 return std::make_pair(mBuffer + mBufferPos, mBufferSize - mBufferPos);
1055}
1056
1057char*
1059{
1060 int currentPos = (int)mBufferPos + bytesRead;
1061 if (currentPos > 0 && extraBytes > 0)
1062 {
1063 if (((size_t)currentPos + (size_t)extraBytes) > mBufferSize)
1064 {
1065 mBufferSize = currentPos + extraBytes;
1066 char* buffer = MsgHeaderScanner::allocateBuffer(mBufferSize);
1067 memcpy(buffer, mBuffer, currentPos);
1068 delete[] mBuffer;
1069 mBuffer = buffer;
1070 }
1071 return &mBuffer[currentPos];
1072 }
1073 else
1074 {
1075 resip_assert(0);
1076 return mBuffer;
1077 }
1078}
1079
1080void
1081ConnectionBase::setBuffer(char* bytes, int count)
1082{
1083 mBuffer = bytes;
1084 mBufferPos = 0;
1085 mBufferSize = count;
1086}
1087
1088Transport*
1090{
1092 return mTransport;
1093}
1094
1095const std::shared_ptr<const ConnectionInfo>&
1096ConnectionBase::getConnectionInfo()
1097{
1098 // Building it once is enough: a TLS connection finishes its handshake, and a
1099 // WebSocket connection its Upgrade, before any SIP message can arrive on it
1100 if(!mConnectionInfoBuilt)
1101 {
1102 mConnectionInfoBuilt = true;
1103 std::shared_ptr<ConnectionInfo> info;
1104#ifdef USE_SSL
1105 TlsConnection* tlsConnection = dynamic_cast<TlsConnection*>(this);
1106 if(tlsConnection)
1107 {
1108 info = std::make_shared<ConnectionInfo>();
1109 tlsConnection->getPeerNames(info->mTlsPeerNames);
1110 info->mTlsSni = tlsConnection->getSni();
1111 }
1112#endif
1113 WsConnectionBase* wsConnectionBase = dynamic_cast<WsConnectionBase*>(this);
1114 if(wsConnectionBase)
1115 {
1116 if(!info)
1117 {
1118 info = std::make_shared<ConnectionInfo>();
1119 }
1120 info->mWsCookies = wsConnectionBase->getCookies();
1121 info->mWsCookieContext = wsConnectionBase->getWsCookieContext();
1122 }
1123 mConnectionInfo = std::move(info);
1124 }
1125 return mConnectionInfo;
1126}
1127
1129resip::operator<<(EncodeStream& strm,
1130 const resip::ConnectionBase& c)
1131
1132{
1133 strm << "CONN_BASE: " << &c << " " << c.mWho;
1134 return strm;
1135}
1136
1137/* ====================================================================
1138 * The Vovida Software License, Version 1.0
1139 *
1140 * Copyright (c) 2026 SIP Spectrum, Inc. https://www.sipspectrum.com
1141 * Copyright (c) 2000
1142 *
1143 * Redistribution and use in source and binary forms, with or without
1144 * modification, are permitted provided that the following conditions
1145 * are met:
1146 *
1147 * 1. Redistributions of source code must retain the above copyright
1148 * notice, this list of conditions and the following disclaimer.
1149 *
1150 * 2. Redistributions in binary form must reproduce the above copyright
1151 * notice, this list of conditions and the following disclaimer in
1152 * the documentation and/or other materials provided with the
1153 * distribution.
1154 *
1155 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1156 * and "Vovida Open Communication Application Library (VOCAL)" must
1157 * not be used to endorse or promote products derived from this
1158 * software without prior written permission. For written
1159 * permission, please contact vocal@vovida.org.
1160 *
1161 * 4. Products derived from this software may not be called "VOCAL", nor
1162 * may "VOCAL" appear in their name, without prior written
1163 * permission of Vovida Networks, Inc.
1164 *
1165 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1166 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1167 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1168 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1169 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1170 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1171 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1172 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1173 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1174 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1175 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1176 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1177 * DAMAGE.
1178 *
1179 * ====================================================================
1180 *
1181 * This software consists of voluntary contributions made by Vovida
1182 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1183 * Inc. For more information on Vovida Networks, Inc., please see
1184 * <http://www.vovida.org/>.
1185 *
1186 * vi: set shiftwidth=3 expandtab:
1187 */
1188
#define RESIP_SIP_MSG_MAX_BYTES
static const Data cookie("z9hG4bK")
#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 ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
#define resip_assert_not_null(x)
The abstract base-class for all exceptions thrown by resip code.
void addCompressorsToStack(osc::Stack *)
osc::StateHandler & getStateHandler()
@ REJECTING_NEW_WORK
Overloaded, should refuse new work.
@ REJECTING_NON_ESSENTIAL
Rejecting all work that is non-essential to the health of the system (ie, if dropping something is li...
virtual Transport * transport() const
void setFailureReason(TransportFailure::FailureReason failReason, int subCode, const Data &failureString)
char * getWriteBufferForExtraBytes(int bytesRead, int extraBytes)
TransmissionFormat mSendingTransmissionFormat
bool wsProcessData(int bytesRead)
virtual void onWsClose(const Data &payload)
osc::TcpStream * mSigcompFramer
std::pair< char *, size_t > getWriteBuffer()
bool wsProcessHandshake(int bytesRead, bool &dropConnection)
void decompressNewBytes(int bytesRead)
virtual void onSingleCRLF()
std::pair< char *, size_t > getCurrentWriteBuffer()
bool preparseNewBytes(int bytesRead)
std::list< SendData * > mOutstandingSends
void setBuffer(char *bytes, int count)
std::list< Data > mAdditionalFailureStrings
void addAdditionalFailureString(const Data &additionalFailureString)
virtual void onWsPing(const Data &payload)
void wsParseCookies(CookieList &cookieList, const SipMessage *message)
virtual void onDoubleCRLF()
FlowKey getFlowKey() const
TransportFailure::FailureReason mFailureReason
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 base64encode(bool useUrlSafe=false) const
Performs RFC 3548 Base 64 encoding of the contents of this data.
Definition Data.cxx:2682
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_t size_type
Definition Data.hxx:94
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
Used to accumlate data written to the stream in a DigestBuffer and convert the data to Digest.
void prepareForMessage(SipMessage *msg)
unsigned int getHeaderCount() const
MsgHeaderScanner::ScanChunkResult scanChunk(char *chunk, unsigned int chunkLength, char **unprocessedCharPtr)
static char * allocateBuffer(size_t size)
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipWhitespace()
CurrentPosition skipToChar(char c)
CurrentPosition position() const
CurrentPosition skipToOneOf(const char *cs)
CurrentPosition skipChar()
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
static const char * Whitespace
BaseException used to indicate parse failures.
const Uri & uri() const
Represents a SIP message.
void addBuffer(char *buf)
bool isRequest() const
Returns true if message is a request, false otherwise.
void setConnectionInfo(std::shared_ptr< const ConnectionInfo > connectionInfo) noexcept
void setBody(const char *start, uint32_t len)
void setTlsDomain(const Data &domain)
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
const RequestLine & const_header(const RequestLineType &l) const
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
void setSource(const Tuple &tuple)
static const char * SEMI_COLON
Definition Symbols.hxx:30
static const char *const WebsocketMagicGUID
Definition Symbols.hxx:79
static const char * CRLFCRLF
Definition Symbols.hxx:22
static const char * EQUALS
Definition Symbols.hxx:29
static const char * CRLF
Definition Symbols.hxx:21
static const char * DOUBLE_QUOTE
Definition Symbols.hxx:26
This class is used to get the current system time.
Definition Timer.hxx:31
const Data & getSni() const
SNI the client sent in its ClientHello, for connections we accepted (server mode); empty if it sent n...
void getPeerNames(std::list< Data > &peerNames) const
This message is used to indicate that the TransportSelector has sent a sip message using either relia...
The base class for Transport classes.
Definition Transport.hxx:83
const Tuple & getTuple() const
std::unique_ptr< SendData > make503(SipMessage &msg, uint16_t retryAfter)
virtual void pushRxMsgUp(SipMessage *msg)
unsigned int getKey() const
static void stampReceived(SipMessage *request)
uint32_t getExpectedWaitForIncoming() const
void fail(const Data &tid, TransportFailure::FailureReason reason=TransportFailure::Failure, int subCode=0)
Posts a TransportFailure to the TransactionMessage Fifo.
bool basicCheck(const SipMessage &msg)
Perform basic sanity checks on message.
const Data & tlsDomain() const
CongestionManager::RejectionBehavior getRejectionBehaviorForIncoming() const
void flowTerminated(const Tuple &flow, TransportFailure::FailureReason failureReason, int failureSubCode, const Data &failureString, const std::list< Data > additionalFailureStrings)
Posts a ConnectionTerminated message to TransactionMessage Fifo.
virtual void send(std::unique_ptr< SendData > data)=0
Represents a network address.
Definition Tuple.hxx:59
FlowKey mFlowKey
This is a (largely) opaque key that subclasses of Transport will use to help record/find flows.
Definition Tuple.hxx:189
TransportKey mTransportKey
Definition Tuple.hxx:190
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
Represents the "via-parm" element in the RFC 3261 grammar.
Definition Via.hxx:18
bool exists(const Param< Via > &paramType) const
Definition Via.cxx:266
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
std::shared_ptr< WsCookieContextFactory > cookieContextFactory() const noexcept
std::shared_ptr< WsConnectionValidator > connectionValidator() const noexcept
const CookieList & getCookies() const noexcept
void setWsCookieContext(std::shared_ptr< WsCookieContext > wsCookieContext) noexcept
void setCookies(const CookieList &cookies)
std::shared_ptr< WsCookieContext > getWsCookieContext() const noexcept
std::unique_ptr< Data > processBytes(uint8_t *input, Data::size_type len, bool &dropConnection)
static const uint8_t OpClose
static const uint8_t OpPing
bool popControlFrame(ControlFrame &frame)
dcm! – add UnusedChecking(_enum) below;
const _Tp & resipMin(const _Tp &__a, const _Tp &__b)
Definition compat.hxx:182
unsigned long FlowKey
Definition Tuple.hxx:37
unsigned int uint32_t
Definition Stun.hxx:34
RequestLineType h_RequestLine
Definition Headers.cxx:347
const _Tp & resipMax(const _Tp &__a, const _Tp &__b)
Definition compat.hxx:194
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)
unsigned char uint8_t
Definition Stun.hxx:29
std::vector< Cookie > CookieList
Definition Cookie.hxx:35
#define EncodeStream