1#if defined(HAVE_CONFIG_H)
29#include <osc/TcpStream.h>
30#include <osc/SigcompMessage.h>
31#include <osc/StateChanges.h>
36#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
39ConnectionBase::connectionStates[
ConnectionBase::MAX][32] = {
"NewMessage",
"ReadingHeaders",
"PartialBody" };
41#ifndef RESIP_SIP_MSG_MAX_BYTES
42#define RESIP_SIP_MSG_MAX_BYTES 10485760
50 mTransport(transport),
54 mCompression(compression),
59 mSendingTransmissionFormat(
Unknown),
60 mReceivingTransmissionFormat(
Unknown),
65 mWsFrameExtractor((
Data::size_type)messageSizeMax),
66 mLastUsed(
Timer::getTimeMs()),
67 mConnState(NewMessage)
69 DebugLog (<<
"ConnectionBase::ConnectionBase, who: " <<
mWho <<
" " <<
this);
73 DebugLog (<<
"Compression enabled for connection, who: " <<
mWho <<
" " <<
this);
79 DebugLog (<<
"Compression disabled for connection, who: " <<
mWho <<
" " <<
this);
82 DebugLog (<<
"No compression library available, who: " <<
mWho <<
" " <<
this);
116 DebugLog (<<
"ConnectionBase::~ConnectionBase, who: " <<
mWho <<
" " <<
this);
145 DebugLog(<<
"In State: " << connectionStates[mConnState] <<
", who: " <<
mWho <<
" " <<
this);
155 DebugLog(<<
"Got incoming double-CRLF keepalive (aka ping), who: " <<
mWho <<
" " <<
this);
170 else if (bytesRead >= 2 && strncmp(mBuffer + mBufferPos,
Symbols::CRLF, 2) == 0)
191 DebugLog(<<
"ConnectionBase::process setting source, who: " <<
mWho <<
" " <<
this);
200 unsigned int chunkLength = (
unsigned int)mBufferPos + bytesRead;
201 char *unprocessedCharPtr;
205 &unprocessedCharPtr);
209 WarningLog(<<
"Discarding preparse, who: " <<
mWho <<
" " <<
this);
220 WarningLog(<<
"Discarding preparse; too many headers, who: " <<
mWho <<
" " <<
this);
229 unsigned int numUnprocessedChars =
230 (
unsigned int)((mBuffer + chunkLength) - unprocessedCharPtr);
235 WarningLog(<<
"Discarding preparse; header-field-value (or "
236 "header name) too long, who: " <<
mWho <<
" " <<
this);
245 if(numUnprocessedChars==chunkLength)
249 size_t size = numUnprocessedChars*3/2;
259 catch(std::bad_alloc&)
261 ErrLog(<<
"Failed to alloc a buffer during preparse, who: " <<
mWho <<
" " <<
this);
264 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars);
267 mBufferPos = numUnprocessedChars;
279 if (numUnprocessedChars == 0)
288 catch(std::bad_alloc&)
290 ErrLog(<<
"Failed to alloc a buffer during preparse, who: " <<
mWho <<
" " <<
this);
299 size_t size = numUnprocessedChars*3/2;
309 catch(std::bad_alloc&)
311 ErrLog(<<
"Failed to alloc a buffer during preparse, who: " <<
mWho <<
" " <<
this);
314 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars);
316 mBufferPos = numUnprocessedChars;
323 size_t contentLength = 0;
328 contentLength=mMessage->
const_header(h_ContentLength).value();
332 WarningLog(<<
"Malformed Content-Length in connection-based transport"
333 ". Not much we can do to fix this, who: " <<
mWho <<
" " <<
this <<
": " << e);
344 if(contentLength > messageSizeMax || contentLength < 0)
346 WarningLog(<<
"Content-Length in connection-based "
347 "transport exceeds maximum " << messageSizeMax <<
", who: " <<
mWho <<
" " <<
this);
357 if (numUnprocessedChars < contentLength)
360 DebugLog(<<
"partial body received, who: " <<
mWho <<
" " <<
this);
365 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars);
366 mBufferPos = numUnprocessedChars;
367 mBufferSize = newSize;
377 int overHang = numUnprocessedChars - (int)contentLength;
384 size_t size = overHang*3/2;
391 unprocessedCharPtr + contentLength,
397 DebugLog (<<
"Extra bytes after message: " << overHang <<
", who: " <<
mWho <<
" " <<
this);
400 bytesRead = overHang;
404 if (contentLength > 0)
421 std::unique_ptr<SendData> tryLater(
transport()->make503(*mMessage, expectedWait));
429 else if (!
transport()->basicCheck(*mMessage))
437 DebugLog(<<
"##Connection, who: " <<
mWho <<
" " <<
this <<
" received: " << *mMessage);
453 size_t contentLength = 0;
457 contentLength = mMessage->
const_header(h_ContentLength).value();
461 WarningLog(<<
"Malformed Content-Length in connection-based transport"
462 ". Not much we can do to fix this, who: " <<
mWho <<
" " <<
this <<
": " << e);
472 mBufferPos += bytesRead;
473 if (mBufferPos >= contentLength)
475 size_t overHang = mBufferPos - contentLength;
476 char *overHangStart = mBuffer + contentLength;
486 size_t size = overHang * 3 / 2;
492 memcpy(newBuffer, overHangStart, overHang);
497 DebugLog(<<
"Extra bytes after message: " << overHang <<
", who: " <<
mWho <<
" " <<
this);
500 bytesRead = (int)overHang;
520 std::unique_ptr<SendData> tryLater =
transport()->
make503(*mMessage, expectedWait);
528 else if (!
transport()->basicCheck(*mMessage))
535 DebugLog(<<
"##ConnectionBase, who: " <<
mWho <<
" " <<
this <<
" received: " << *mMessage);
548 else if (mBufferPos == mBufferSize)
552 size_t newSize =
resipMin(mBufferSize*3/2, contentLength);
556 newBuffer=
new char[newSize];
558 catch(std::bad_alloc&)
560 ErrLog(<<
"Failed to alloc a buffer while receiving body, who: " <<
mWho <<
" " <<
this);
563 memcpy(newBuffer, mBuffer, mBufferSize);
581 StringCategories::const_iterator it = message->
header(h_Cookies).begin();
582 for (; it != message->
header(h_Cookies).end(); ++it)
590 pb.
data(name, anchor);
597 pb.
data(value, anchor);
603 pb.
data(value, anchor);
607 cookieList.push_back(
cookie);
628 dropConnection =
false;
630 if(mBufferPos + bytesRead > messageSizeMax)
632 WarningLog(<<
"Too many bytes received during WS handshake, dropping connection. Max message size = " << messageSizeMax <<
", who: " <<
mWho <<
" " <<
this);
633 dropConnection =
true;
644 if (!scanMsgHeader(bytesRead))
655 std::shared_ptr<WsCookieContext> wsCookieContext;
656 if (mMessage->
exists(h_Cookies))
675 WarningLog(<<
"Failed to parse cookies into WsCookieContext, who: " <<
mWho <<
" " <<
this <<
": " << ex);
678 std::shared_ptr<WsConnectionValidator> wsConnectionValidator = wsConnectionBase->
connectionValidator();
679 if(wsConnectionValidator &&
680 (!wsCookieContext || !wsConnectionValidator->validateConnection(*wsCookieContext)))
682 ErrLog(<<
"WebSocket cookie validation failed, dropping connection, who: " <<
mWho <<
" " <<
this);
690 dropConnection =
true;
695 std::unique_ptr<Data> wsResponsePtr = makeWsHandshakeResponse();
697 if (wsResponsePtr.get())
699 DebugLog (<<
"WebSocket upgrade accepted, cookie count = " << cookieList.size() <<
", who: " <<
mWho <<
" " <<
this);
703 *wsResponsePtr.get(),
710 ErrLog(<<
"Failed to parse WebSocket initialization request, who: " <<
mWho <<
" " <<
this);
714 dropConnection =
true;
720 ErrLog(<<
"Cannot auth request is missing, who: " <<
mWho <<
" " <<
this <<
": " << e);
724 dropConnection =
true;
736ConnectionBase::scanMsgHeader(
int bytesRead)
739 char *unprocessedCharPtr;
745 StackLog(<<
"Failed to parse message, more bytes needed, who: " <<
mWho <<
" " <<
this);
750 mBufferPos += bytesRead;
757ConnectionBase::makeWsHandshakeResponse()
759 std::unique_ptr<Data> responsePtr;
760 if(isUsingSecWebSocketKey())
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"));
770 *responsePtr +=
"Sec-WebSocket-Accept: " + wsAcceptKey +
"\r\n\r\n";
772 else if(isUsingDeprecatedSecWebSocketKeys())
774 ErrLog(<<
"WS client wants to use depracated protocol version, unsupported, who: " <<
mWho <<
" " <<
this);
778 ErrLog(<<
"No SecWebSocketKey header, who: " <<
mWho <<
" " <<
this);
783bool ConnectionBase::isUsingDeprecatedSecWebSocketKeys()
786 return mMessage->
exists(h_SecWebSocketKey1) &&
787 mMessage->
exists(h_SecWebSocketKey2);
790bool ConnectionBase::isUsingSecWebSocketKey()
793 return mMessage->
exists(h_SecWebSocketKey);
799 bool dropConnection =
false;
801 std::unique_ptr<Data> msg = mWsFrameExtractor.
processBytes((
uint8_t*)mBuffer, bytesRead, dropConnection);
808 if(msg->size() == 4 && memcmp(msg->data(),
"\r\n\r\n", 4) == 0)
811 StackLog(<<
"got a SIP ping embedded in WebSocket frame, replying, who: " <<
mWho <<
" " <<
this);
813 msg = mWsFrameExtractor.
processBytes(0, 0, dropConnection);
826 char *sipBuffer = (
char *)msg->data();
829 char *unprocessedCharPtr;
830 if (mMsgHeaderScanner.
scanChunk(sipBuffer,
831 (
unsigned int)msg_len,
832 &unprocessedCharPtr) !=
835 StackLog(<<
"Scanner rejecting WebSocket SIP message as unparsable, length=" << msg_len <<
", who: " <<
mWho <<
" " <<
this);
841 unsigned int used = (
unsigned int)(unprocessedCharPtr - sipBuffer);
842 if (mMessage && (used < msg_len))
863 ErrLog(<<
"We don't have a valid SIP message, maybe drop the connection? who: " <<
mWho <<
" " <<
this);
865 msg = mWsFrameExtractor.
processBytes(0, 0, dropConnection);
881 const unsigned char* code = (
const unsigned char*)control.
payload.
data();
882 status =
Data((code[0] << 8) | code[1]);
884 InfoLog(<<
"WebSocket closed by the peer, status " << status <<
", closing connection, who: " <<
mWho <<
" " <<
this);
889 StackLog(<<
"got a WebSocket Ping, replying, who: " <<
mWho <<
" " <<
this);
893 StackLog(<<
"got a WebSocket Pong, who: " <<
mWho <<
" " <<
this);
918 size_t bytesUncompressed;
919 osc::StateChanges *sc = 0;
920 char *uncompressed =
new char[65536];
921 while ((bytesUncompressed =
mSigcompStack->uncompressMessage(
924 DebugLog (<<
"Uncompressed Connection-oriented message, who: " <<
mWho <<
" " <<
this);
932 memmove(sipBuffer, uncompressed, bytesUncompressed);
935 char *unprocessedCharPtr;
936 if (mMsgHeaderScanner.
scanChunk(sipBuffer,
938 &unprocessedCharPtr) !=
941 StackLog(<<
"Scanner rejecting compressed message as unparsable, who: " <<
mWho <<
" " <<
this);
947 unsigned int used = unprocessedCharPtr - sipBuffer;
948 if (mMessage && (used < bytesUncompressed))
950 mMessage->
setBody(sipBuffer+used, bytesUncompressed-used);
953 if (mMessage && !
transport()->basicCheck(*mMessage))
970 if (via.
exists(p_sigcompId))
992 Data compId = via.
param(p_branch).getSigcompCompartment();
1009 delete [] uncompressed;
1021 Data(nack->getStreamMessage(), nack->getStreamLength()),
1034std::pair<char*, size_t>
1041 DebugLog (<<
"Creating buffer for, who: " <<
mWho <<
" " <<
this);
1051std::pair<char*, size_t>
1054 return std::make_pair(mBuffer + mBufferPos, mBufferSize - mBufferPos);
1060 int currentPos = (int)mBufferPos + bytesRead;
1061 if (currentPos > 0 && extraBytes > 0)
1063 if (((
size_t)currentPos + (
size_t)extraBytes) > mBufferSize)
1065 mBufferSize = currentPos + extraBytes;
1067 memcpy(buffer, mBuffer, currentPos);
1071 return &mBuffer[currentPos];
1085 mBufferSize = count;
1095const std::shared_ptr<const ConnectionInfo>&
1096ConnectionBase::getConnectionInfo()
1100 if(!mConnectionInfoBuilt)
1102 mConnectionInfoBuilt =
true;
1103 std::shared_ptr<ConnectionInfo> info;
1108 info = std::make_shared<ConnectionInfo>();
1110 info->mTlsSni = tlsConnection->
getSni();
1114 if(wsConnectionBase)
1118 info = std::make_shared<ConnectionInfo>();
1120 info->mWsCookies = wsConnectionBase->
getCookies();
1123 mConnectionInfo = std::move(info);
1125 return mConnectionInfo;
1133 strm <<
"CONN_BASE: " << &c <<
" " << c.
mWho;
#define RESIP_SIP_MSG_MAX_BYTES
static const Data cookie("z9hG4bK")
#define WarningLog(args_)
#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)
virtual ~ConnectionBase()
char * getWriteBufferForExtraBytes(int bytesRead, int extraBytes)
Compression & mCompression
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()
osc::Stack * mSigcompStack
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.
static const Data Empty
Constant that represents a zero-length data.
Data base64encode(bool useUrlSafe=false) const
Performs RFC 3548 Base 64 encoding of the contents of this data.
bool empty() const noexcept
Checks whether the Data is empty.
size_type size() const noexcept
Returns the number of bytes in this Data.
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Used to accumlate data written to the stream in a DigestBuffer and convert the data to Digest.
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.
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
static const char *const WebsocketMagicGUID
static const char * CRLFCRLF
static const char * EQUALS
static const char * DOUBLE_QUOTE
This class is used to get the current system time.
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.
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.
FlowKey mFlowKey
This is a (largely) opaque key that subclasses of Transport will use to help record/find flows.
TransportKey mTransportKey
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Represents the "via-parm" element in the RFC 3261 grammar.
bool exists(const Param< Via > ¶mType) const
const Data & param(const ExtensionParameter ¶m) 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
dcm! – add UnusedChecking(_enum) below;
const _Tp & resipMin(const _Tp &__a, const _Tp &__b)
RequestLineType h_RequestLine
const _Tp & resipMax(const _Tp &__a, const _Tp &__b)
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)
std::vector< Cookie > CookieList